From 6e5d23262cf6cb974fc619fa989dc6a80454c3f1 Mon Sep 17 00:00:00 2001 From: nxxc Date: Thu, 10 Dec 2020 18:00:24 +0900 Subject: [PATCH 01/44] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기능 목록 업데이트 --- README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/README.md b/README.md index e97a1d649..5d72a1e83 100644 --- a/README.md +++ b/README.md @@ -112,3 +112,36 @@ - **기능을 구현하기 전에 javascript-subway-precourse/docs/README.md 파일에 구현할 기능 목록**을 정리해 추가한다. - **git의 commit 단위는 앞 단계에서 README.md 파일에 정리한 기능 목록 단위로 추가**한다. - [프리코스 과제 제출](https://github.com/woowacourse/woowacourse-docs/tree/master/precourse) 문서 절차를 따라 미션을 제출한다. + +## 🔥 기능 목록 + +- 기능 + - [ ] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) + +- 역 관련 기능 + - [ ] 사용자가 역 이름을 추가할 수 있게해야 한다. + - [ ] 역 이름이 중복되는지 확인해야한다. + - [ ] 역 이름이 2글자 이상인지 확인해야 한다 + - [ ] 사용자가 입력한 역들을 차례대로 출력해야 한다. + - [ ] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. + - [ ] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. + - [ ] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. + +- 노선 관련 기능 + - [ ] 노선 이름을 등록 할 수 있게 한다. + - [ ] 노선 이름이 중복되는지 확인해야한다. + - [ ] 상행 종점 하행 종점을 등록한 역 목록에서 선택할 수 있게 해야한다. + - [ ] 상행 종점과 하행 종점이 같은지 확인해야 한다. + - [ ] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. + - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. + +- 구간 관련 기능 + - [ ] 사용자가 등록한 노선을 표시해야한다. + - [ ] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. + - [ ] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. + - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. + - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. + - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. + +- 노선도 출력 기능 + - [ ] 노선의 상행종점부터 하행종점까지 순서대로 목록을 표시해야 한다. \ No newline at end of file From 6959eb2a210d1203526bad0e11fdbb459e46d109 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 15:05:45 +0900 Subject: [PATCH 02/44] =?UTF-8?q?[feat]=20=ED=94=84=EB=A1=9C=EC=A0=9D?= =?UTF-8?q?=ED=8A=B8=20=EA=B8=B0=EB=B3=B8=20=EC=85=8B=ED=8C=85=20&=20HTML?= =?UTF-8?q?=20=EB=A7=88=ED=81=AC=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - css selector 기반으로 HTML 마크업을 작성하였다. - 프로젝트의 기본 폴더를 구성하였다. --- .vscode/settings.json | 3 + README.md | 66 +++++++++++------- index.html | 115 +++++++++++++++++++++++++++++++- src/factory/Component.js | 1 + src/index.js | 3 + src/managers/LineManager.js | 1 + src/managers/MapPrintManager.js | 1 + src/managers/SectionManager.js | 1 + src/managers/StationManager.js | 1 + src/share/selector.js | 52 +++++++++++++++ 10 files changed, 219 insertions(+), 25 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 src/factory/Component.js create mode 100644 src/managers/LineManager.js create mode 100644 src/managers/MapPrintManager.js create mode 100644 src/managers/SectionManager.js create mode 100644 src/managers/StationManager.js create mode 100644 src/share/selector.js diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..aef844305 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "liveServer.settings.port": 5501 +} \ No newline at end of file diff --git a/README.md b/README.md index 5d72a1e83..b9dd939c3 100644 --- a/README.md +++ b/README.md @@ -3,20 +3,23 @@ ## 🚀 기능 요구사항 ### 지하철 역 관련 기능 + - 지하철 역을 등록하고 삭제할 수 있다. (단, 노선에 등록된 역은 삭제할 수 없다) - 중복된 지하철 역 이름이 등록될 수 없다. - 지하철 역은 2글자 이상이어야 한다. - 지하철 역의 목록을 조회할 수 있다. ### 지하철 노선 관련 기능 + - 지하철 노선을 등록하고 삭제할 수 있다. - 중복된 지하철 노선 이름이 등록될 수 없다. - 노선 등록 시 상행 종점역과 하행 종점역을 입력받는다. - 지하철 노선의 목록을 조회할 수 있다. ### 지하철 구간 추가 기능 + - 지하철 노선에 구간을 추가하는 기능은 노선에 역을 추가하는 기능이라고도 할 수 있다. - - 역과 역사이를 구간이라 하고 이 구간들의 모음이 노선이다. + - 역과 역사이를 구간이라 하고 이 구간들의 모음이 노선이다. - 하나의 역은 여러개의 노선에 추가될 수 있다. - 역과 역 사이에 새로운 역이 추가 될 수 있다. - 노선에서 갈래길은 생길 수 없다. @@ -24,6 +27,7 @@ ### 지하철 구간 삭제 기능 + - 노선에 등록된 역을 제거할 수 있다. - 종점을 제거할 경우 다음 역이 종점이 된다. - 노선에 포함된 역이 두개 이하일 때는 역을 제거할 수 없다. @@ -31,6 +35,7 @@ ### 지하철 노선에 등록된 역 조회 기능 + - 노선의 상행 종점부터 하행 종점까지 연결된 순서대로 역 목록을 조회할 수 있다.
@@ -38,32 +43,38 @@ ## 💻 프로그램 실행 결과 ### 역관리 + ### 노선관리 + ### 구간관리 + ### 노선도 출력 - + ## ✅ 프로그래밍 요구사항 ### 메뉴 버튼 + - 역 관리 button 태그는 `#station-manager-button` id값을 가진다. - 노선 관리 button 태그는 `#line-manager-button` id값을 가진다. - 구간 관리 button 태그는 `#section-manager-button` id값을 가진다. - 지하철 노선도 출력 관리 button 태그는 `#map-print-manager-button` id값을 가진다. ### 지하철 역 관련 기능 + - 지하철 역을 입력하는 input 태그는 `#station-name-input` id값을 가진다. - 지하철 역을 추가하는 button 태그는 `#station-add-button` id값을 가진다. - 지하철 역을 삭제하는 button 태그는 `.station-delete-button` class값을 가진다. ### 지하철 노선 관련 기능 + - 지하철 노선의 이름을 입력하는 input 태그는 `#line-name-input` id값을 가진다. - 지하철 노선의 상행 종점을 선택하는 select 태그는 `#line-start-station-selector` id값을 가진다. - 지하철 노선의 하행 종점을 선택하는 select 태그는 `#line-end-station-selector` id값을 가진다. @@ -71,6 +82,7 @@ - 지하철 노선을 삭제하는 button 태그는 `.line-delete-button` class값을 가진다. ### 지하철 구간 추가 기능 + - 지하철 노선을 선택하는 button 태그는 `.section-line-menu-button` class값을 가진다. - 지하철 구간을 설정할 역 select 태그는 `#section-station-selector` id값을 가진다. - 지하철 구간의 순서를 입력하는 input 태그는 `#section-order-input` id값을 가진다. @@ -78,6 +90,7 @@ - 지하철 구간을 제거하는 button 태그는 `.section-delete-button` class값을 가진다. ### 지하철 노선도 출력 기능 + - 지하철 노선도 출력 버튼을 누르면 `
` 태그를 만들고 해당 태그 내부에 노선도를 출력한다. ### 기존 요구사항 @@ -101,7 +114,8 @@ - [https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Template_literals) ### 추가된 요구사항 -- [data](https://developer.mozilla.org/ko/docs/Learn/HTML/Howto/%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%86%8D%EC%84%B1_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)속성을 활용하여 html 태그에 역, 노선, 구간의 유일한 데이터 값들을 관리한다. + +- [data](https://developer.mozilla.org/ko/docs/Learn/HTML/Howto/%EB%8D%B0%EC%9D%B4%ED%84%B0_%EC%86%8D%EC%84%B1_%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0)속성을 활용하여 html 태그에 역, 노선, 구간의 유일한 데이터 값들을 관리한다. - [localStorage](https://developer.mozilla.org/ko/docs/Web/API/Window/localStorage)를 이용하여, 새로고침하더라도 가장 최근에 작업한 정보들을 불러올 수 있도록 한다.
@@ -116,32 +130,36 @@ ## 🔥 기능 목록 - 기능 - - [ ] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) + + - [ ] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) - 역 관련 기능 - - [ ] 사용자가 역 이름을 추가할 수 있게해야 한다. - - [ ] 역 이름이 중복되는지 확인해야한다. - - [ ] 역 이름이 2글자 이상인지 확인해야 한다 - - [ ] 사용자가 입력한 역들을 차례대로 출력해야 한다. - - [ ] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. - - [ ] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. - - [ ] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. + + - [ ] 사용자가 역 이름을 추가할 수 있게해야 한다. + - [ ] 역 이름이 중복되는지 확인해야한다. + - [ ] 역 이름이 2글자 이상인지 확인해야 한다 + - [ ] 사용자가 입력한 역들을 차례대로 출력해야 한다. + - [ ] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. + - [ ] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. + - [ ] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. - 노선 관련 기능 - - [ ] 노선 이름을 등록 할 수 있게 한다. - - [ ] 노선 이름이 중복되는지 확인해야한다. - - [ ] 상행 종점 하행 종점을 등록한 역 목록에서 선택할 수 있게 해야한다. - - [ ] 상행 종점과 하행 종점이 같은지 확인해야 한다. - - [ ] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. - - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. + + - [ ] 노선 이름을 등록 할 수 있게 한다. + - [ ] 노선 이름이 중복되는지 확인해야한다. + - [ ] 상행 종점 하행 종점을 등록한 역 목록에서 선택할 수 있게 해야한다. + - [ ] 상행 종점과 하행 종점이 같은지 확인해야 한다. + - [ ] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. + - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. - 구간 관련 기능 - - [ ] 사용자가 등록한 노선을 표시해야한다. - - [ ] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. - - [ ] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. - - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. - - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. - - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. + + - [ ] 사용자가 등록한 노선을 표시해야한다. + - [ ] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. + - [ ] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. + - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. + - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. + - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. - 노선도 출력 기능 - - [ ] 노선의 상행종점부터 하행종점까지 순서대로 목록을 표시해야 한다. \ No newline at end of file + - [ ] 노선의 상행종점부터 하행종점까지 순서대로 목록을 표시해야 한다. diff --git a/index.html b/index.html index fc99deac2..c1a5cb59f 100644 --- a/index.html +++ b/index.html @@ -3,10 +3,123 @@ 지하철 노선도 관리 +
-

🚇 지하철 노선도 관리

+

🚇 지하철 노선도 관리

+ +
+
+ + + +
+
+

🚉 지하철 역 목록

+ + + + + + + + +
역 이름설정
+
+
+
+
+ + +

+ 상행 종점 + +

+

+ 하행 종점 + +

+ +
+
+

+

🚉 지하철 노선 목록

+ + + + + + + + + + +
노선 이름상행 종점역하행 종점역설정
+ +
+
+
+

구간을 수정할 노선을 선택해 주세요.

+ +
+
+

n호선 관리

+

구간 등록

+ + + +
+
+

+

🚉 지하철 노선 목록

+ + + + + + + + + +
순서이름설정
+ +
+
+
+
diff --git a/src/factory/Component.js b/src/factory/Component.js new file mode 100644 index 000000000..3d7b55df1 --- /dev/null +++ b/src/factory/Component.js @@ -0,0 +1 @@ +export default class Component {} diff --git a/src/index.js b/src/index.js index e69de29bb..f9410d422 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,3 @@ +export default class SubwayManager {} + +new SubwayManager(); diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js new file mode 100644 index 000000000..56969a29a --- /dev/null +++ b/src/managers/LineManager.js @@ -0,0 +1 @@ +export default class LineManager {} diff --git a/src/managers/MapPrintManager.js b/src/managers/MapPrintManager.js new file mode 100644 index 000000000..db9bb6a7a --- /dev/null +++ b/src/managers/MapPrintManager.js @@ -0,0 +1 @@ +export default class MapPrintManager {} diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js new file mode 100644 index 000000000..2de34feea --- /dev/null +++ b/src/managers/SectionManager.js @@ -0,0 +1 @@ +export default class SectionManager {} diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js new file mode 100644 index 000000000..1c5418701 --- /dev/null +++ b/src/managers/StationManager.js @@ -0,0 +1 @@ +export default class StationManager {} diff --git a/src/share/selector.js b/src/share/selector.js new file mode 100644 index 000000000..c4e83d1ae --- /dev/null +++ b/src/share/selector.js @@ -0,0 +1,52 @@ +export const MENU = Object.freeze({ + MENU_CONTAINER_ID: 'menu', + STATION_MANGER_BUTTON_ID: 'station-manager-button', + LINE_MANAGER_BUTTON_ID: 'line-manager-button', + SECTION_MANAGER_BUTTON_ID: 'section-manager-button', + MAP_PRINT_MANAGER_BUTTON_ID: 'map-print-manager-button', +}); + +export const STATION = Object.freeze({ + STATION_MANAGER_CONTAINER_ID: 'station-manager', + STATION_FORM_ID: 'station-form', + STATION_RESULT_CONTAINER_ID: 'station-result', + STATION_TABLE: 'station-table', + STATION_TABLE_BODY: 'station-table-body', + STATION_NAME_INPUT_ID: 'station-name-input', + STATION_ADD_BUTTON_ID: 'station-add-button', + STATION_DELETE_BUTTON_CLASS: 'station-delete-button', +}); + +export const LINE = Object.freeze({ + LINE_MANAGER_CONTAINER_ID: 'line-manager', + LINE_FORM_ID: 'line-form', + LINE_NAME_INPUT_ID: 'line-name-input', + LINE_START_STATION_SELECTOR_ID: 'line-start-station-selector', + LINE_END_STATION_SELECTOR: 'line-end-station-selector', + LINE_ADD_BUTTON_ID: 'line-add-button', + LINE_DELETE_BUTTON_CLASS: 'line-delete-button', + LINE_RESULT_CONTAINER_ID: 'line-result', + LINE_TABLE: 'line-table', + LINE_TABLE_BODY: 'line-table-body', +}); + +export const SECTION = Object.freeze({ + SECTION_MANAGER_CONTAINER_ID: 'section-manager', + SECTION_LINE_MENU_ID: 'section-line-menu', + SECTION_LINE_MENU_BUTTON_CLASS: 'section-line-menu-button', + SECTION_DETAIL_CONTAINER_ID: 'section-detail', + SECTION_FORM_ID: 'section-form', + SECTION_FORM_HEADER_ID: 'section-form-header', + SECTION_STATION_SELECTOR_ID: 'section-station-selector', + SECTION_ORDER_INPUT_ID: 'section-order-input', + SECTION_ADD_BUTTON_ID: 'section-add-button', + SECTION_DELETE_BUTTON: 'section-delete-button', + SECTION_RESULT_CONTAINER_ID: 'section-result', + SECTION_TABLE: 'section-table', + SECTION_TABLE_BODY: 'section-table-body', +}); + +export const MAP = Object.freeze({ + MAP_PRINT_MANAGER_CONTAINER_ID: 'map-print-manager', + MAP_CLASS: 'map', +}); From a5ba93e1c7ab4b4a86183fb924feacea256f4d7e Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 15:41:30 +0900 Subject: [PATCH 03/44] =?UTF-8?q?[feat]=20=EB=A9=94=EB=89=B4=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=ED=95=B4=EB=8B=B9?= =?UTF-8?q?=ED=95=98=EB=8A=94=20=EB=A9=94=EB=89=B4=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - display 속성을 이용하여 메뉴를 조작하도록 함 - Component class 를 이용하여 manager들의 공통적인 기능을 공유 하도록 함 --- README.md | 2 +- index.html | 8 +++--- src/factory/Component.js | 26 ++++++++++++++++- src/index.js | 49 ++++++++++++++++++++++++++++++++- src/managers/LineManager.js | 8 +++++- src/managers/MapPrintManager.js | 8 +++++- src/managers/SectionManager.js | 8 +++++- src/managers/StationManager.js | 8 +++++- 8 files changed, 106 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index b9dd939c3..1a8bdb0f9 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ - 기능 - - [ ] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) + - [x] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) - 역 관련 기능 diff --git a/index.html b/index.html index c1a5cb59f..d1e36f366 100644 --- a/index.html +++ b/index.html @@ -19,7 +19,7 @@

🚇 지하철 노선도 관리

-
-
+ -
+
-
+
diff --git a/src/factory/Component.js b/src/factory/Component.js index 3d7b55df1..0657fa3fc 100644 --- a/src/factory/Component.js +++ b/src/factory/Component.js @@ -1 +1,25 @@ -export default class Component {} +export default class Component { + constructor(props) { + this.state = {}; + this.managerId = props.managerId; + this.container = document.querySelector(`#${props.containerId}`); + } + + setState(nextData) { + this.state = { + ...this.state, + ...nextData, + }; + this.render(); + } + + show() { + this.container.style.display = 'block'; + } + + hide() { + this.container.style.display = 'none'; + } + + render() {} +} diff --git a/src/index.js b/src/index.js index f9410d422..dcf022bec 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,50 @@ -export default class SubwayManager {} +import Component from './factory/Component.js'; +import LineManager from './managers/lineManager.js'; +import MapPrintManager from './managers/MapPrintManager.js'; +import SectionManager from './managers/SectionManager.js'; +import StationManager from './managers/StationManager.js'; +import { LINE, MAP, MENU, SECTION, STATION } from './share/selector.js'; + +export default class SubwayManager { + constructor() { + this.menu = document.querySelector(`#${MENU.MENU_CONTAINER_ID}`); + console.log(this.menu); + + this.stationManager = new StationManager({ + managerId: MENU.STATION_MANGER_BUTTON_ID, + containerId: STATION.STATION_MANAGER_CONTAINER_ID, + }); + this.lineManager = new LineManager({ + managerId: MENU.LINE_MANAGER_BUTTON_ID, + containerId: LINE.LINE_MANAGER_CONTAINER_ID, + }); + this.sectionManager = new SectionManager({ + managerId: MENU.SECTION_MANAGER_BUTTON_ID, + containerId: SECTION.SECTION_MANAGER_CONTAINER_ID, + }); + this.mapPrintManager = new MapPrintManager({ + managerId: MENU.MAP_PRINT_MANAGER_BUTTON_ID, + containerId: MAP.MAP_PRINT_MANAGER_CONTAINER_ID, + }); + + this.currentManager = this.stationManager; + + this.menu.addEventListener('click', this.changeMenu); + } + + changeMenu = (e) => { + const { nodeName } = e.target; + const { id } = e.target; + if (nodeName !== 'BUTTON') return; + [ + this.stationManager, + this.lineManager, + this.sectionManager, + this.mapPrintManager, + ].forEach((manager) => { + manager.managerId === id ? manager.show() : manager.hide(); + }); + }; +} new SubwayManager(); diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 56969a29a..b3d22de01 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -1 +1,7 @@ -export default class LineManager {} +import Component from '../factory/Component.js'; + +export default class LineManager extends Component { + constructor(props) { + super(props); + } +} diff --git a/src/managers/MapPrintManager.js b/src/managers/MapPrintManager.js index db9bb6a7a..3b640acca 100644 --- a/src/managers/MapPrintManager.js +++ b/src/managers/MapPrintManager.js @@ -1 +1,7 @@ -export default class MapPrintManager {} +import Component from '../factory/Component.js'; + +export default class MapPrintManager extends Component { + constructor(props) { + super(props); + } +} diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index 2de34feea..e21f05d1a 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -1 +1,7 @@ -export default class SectionManager {} +import Component from '../factory/Component.js'; + +export default class SectionManager extends Component { + constructor(props) { + super(props); + } +} diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 1c5418701..ced7d970d 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1 +1,7 @@ -export default class StationManager {} +import Component from '../factory/Component.js'; + +export default class StationManager extends Component { + constructor(props) { + super(props); + } +} From 113380d9c15024c3893e8db0f0514c5a8d72c478 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 15:59:28 +0900 Subject: [PATCH 04/44] =?UTF-8?q?[feat]=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EC=97=AD=20=EC=9D=B4=EB=A6=84=EC=9D=84=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자가 역 이름 입력시 state 객체에 stationList 배열에 역 이름을 추가 할 수 있도록 함. - form 태그의 기본이벤트를 방지해서 새로고침이 일어나지 않도록 함 --- src/index.js | 3 --- src/managers/StationManager.js | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index dcf022bec..85c612fa9 100644 --- a/src/index.js +++ b/src/index.js @@ -8,7 +8,6 @@ import { LINE, MAP, MENU, SECTION, STATION } from './share/selector.js'; export default class SubwayManager { constructor() { this.menu = document.querySelector(`#${MENU.MENU_CONTAINER_ID}`); - console.log(this.menu); this.stationManager = new StationManager({ managerId: MENU.STATION_MANGER_BUTTON_ID, @@ -27,8 +26,6 @@ export default class SubwayManager { containerId: MAP.MAP_PRINT_MANAGER_CONTAINER_ID, }); - this.currentManager = this.stationManager; - this.menu.addEventListener('click', this.changeMenu); } diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index ced7d970d..3b54a7ff4 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1,7 +1,33 @@ import Component from '../factory/Component.js'; +import { STATION } from '../share/selector.js'; export default class StationManager extends Component { constructor(props) { super(props); + this.state.stationList = []; + + this.userInput = this.container.querySelector( + `#${STATION.STATION_NAME_INPUT_ID}`, + ); + this.addBtn = this.container.querySelector( + `#${STATION.STATION_ADD_BUTTON_ID}`, + ); + this.form = this.container.querySelector(`#${STATION.STATION_FORM_ID}`); + + this.form.addEventListener('submit', this.onSubmit); + } + + onSubmit = (event) => { + event.preventDefault(); + const { value } = this.userInput; + this.updateStationList(value); + }; + + updateStationList(station) { + const newStationList = [...this.state.stationList]; + newStationList.push(station); + this.setState({ + stationList: newStationList, + }); } } From 2666da349998b4a8eaa6051e2011dbad3ce36c20 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 16:12:20 +0900 Subject: [PATCH 05/44] =?UTF-8?q?[feat]=20=EC=97=AD=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=EC=9D=B4=20=EC=A4=91=EB=B3=B5=EB=90=98=EB=8A=94=EC=A7=80=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - checkOverlap 함수를 이용하여 중복을 확인한다. --- README.md | 4 ++-- src/managers/StationManager.js | 9 ++++++++- src/share/utils.js | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 src/share/utils.js diff --git a/README.md b/README.md index 1a8bdb0f9..186e16311 100644 --- a/README.md +++ b/README.md @@ -135,8 +135,8 @@ - 역 관련 기능 - - [ ] 사용자가 역 이름을 추가할 수 있게해야 한다. - - [ ] 역 이름이 중복되는지 확인해야한다. + - [x] 사용자가 역 이름을 추가할 수 있게해야 한다. + - [x] 역 이름이 중복되는지 확인해야한다. - [ ] 역 이름이 2글자 이상인지 확인해야 한다 - [ ] 사용자가 입력한 역들을 차례대로 출력해야 한다. - [ ] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 3b54a7ff4..470b2dfc2 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1,5 +1,6 @@ import Component from '../factory/Component.js'; import { STATION } from '../share/selector.js'; +import { checkOverlap } from '../share/utils.js'; export default class StationManager extends Component { constructor(props) { @@ -25,9 +26,15 @@ export default class StationManager extends Component { updateStationList(station) { const newStationList = [...this.state.stationList]; - newStationList.push(station); + if (!this.checkValidity(station)) { + newStationList.push(station); + } this.setState({ stationList: newStationList, }); } + + checkValidity(value) { + return checkOverlap(value, this.state.stationList); + } } diff --git a/src/share/utils.js b/src/share/utils.js new file mode 100644 index 000000000..96e13fa50 --- /dev/null +++ b/src/share/utils.js @@ -0,0 +1 @@ +export const checkOverlap = (value, list) => list.includes(value); From 1fa06ac0eb3fad2e06fd74e9606e2e9c1630718d Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 16:22:08 +0900 Subject: [PATCH 06/44] =?UTF-8?q?[feat]=20=EC=97=AD=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=EC=9D=B4=202=EA=B8=80=EC=9E=90=EC=9D=B4=EC=83=81=EC=9D=B8?= =?UTF-8?q?=EC=A7=80=20=ED=99=95=EC=9D=B8=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - checkOverlap 함수에서 배열에 포함되어있지 않으면 업데이트가 가능하니 리턴값을 수정함 - 최소길이를 상수로 관리해 역이름의 길이를 확인할 수 있도록 함 --- README.md | 2 +- src/managers/StationManager.js | 13 ++++++++----- src/share/utils.js | 4 +++- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 186e16311..057d5270f 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ - [x] 사용자가 역 이름을 추가할 수 있게해야 한다. - [x] 역 이름이 중복되는지 확인해야한다. - - [ ] 역 이름이 2글자 이상인지 확인해야 한다 + - [x] 역 이름이 2글자 이상인지 확인해야 한다 - [ ] 사용자가 입력한 역들을 차례대로 출력해야 한다. - [ ] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. - [ ] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 470b2dfc2..a4e724688 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1,7 +1,8 @@ import Component from '../factory/Component.js'; import { STATION } from '../share/selector.js'; -import { checkOverlap } from '../share/utils.js'; +import { checkOverlap, checkValueLength } from '../share/utils.js'; +const MIN_STATION_NAME_LENGTH = 2; export default class StationManager extends Component { constructor(props) { super(props); @@ -25,16 +26,18 @@ export default class StationManager extends Component { }; updateStationList(station) { + if (!this.checkValidity(station)) return; const newStationList = [...this.state.stationList]; - if (!this.checkValidity(station)) { - newStationList.push(station); - } + newStationList.push(station); this.setState({ stationList: newStationList, }); } checkValidity(value) { - return checkOverlap(value, this.state.stationList); + return ( + checkOverlap(value, this.state.stationList) && + checkValueLength(value, MIN_STATION_NAME_LENGTH) + ); } } diff --git a/src/share/utils.js b/src/share/utils.js index 96e13fa50..e64180ba3 100644 --- a/src/share/utils.js +++ b/src/share/utils.js @@ -1 +1,3 @@ -export const checkOverlap = (value, list) => list.includes(value); +export const checkOverlap = (value, list) => !list.includes(value); + +export const checkValueLength = (value, minLength) => value.length >= minLength; From e9e22ba3ccd98a0d232185e604c9a6c2d6a005c2 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 16:56:14 +0900 Subject: [PATCH 07/44] =?UTF-8?q?[feat]=20=EC=97=AD=20=EB=AA=A9=EB=A1=9D?= =?UTF-8?q?=EC=97=90=20=EC=B0=A8=EB=A1=80=EB=8C=80=EB=A1=9C=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=EC=9D=84=20=EC=B6=9C=EB=A0=A5=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - table의 row에 html data 프로퍼티를 이용해 역 이름과 인덱스를 관리함 - 상태가 변경될 때 마다 목록을 다시 출력할 수 있도록 함 --- README.md | 2 +- src/managers/StationManager.js | 21 +++++++++++++++++++-- src/share/template.js | 6 ++++++ 3 files changed, 26 insertions(+), 3 deletions(-) create mode 100644 src/share/template.js diff --git a/README.md b/README.md index 057d5270f..931b7be12 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,7 @@ - [x] 사용자가 역 이름을 추가할 수 있게해야 한다. - [x] 역 이름이 중복되는지 확인해야한다. - [x] 역 이름이 2글자 이상인지 확인해야 한다 - - [ ] 사용자가 입력한 역들을 차례대로 출력해야 한다. + - [x] 사용자가 입력한 역들을 차례대로 출력해야 한다. - [ ] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. - [ ] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. - [ ] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index a4e724688..dedc4b361 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1,8 +1,10 @@ import Component from '../factory/Component.js'; import { STATION } from '../share/selector.js'; import { checkOverlap, checkValueLength } from '../share/utils.js'; +import { stationTableTemplate } from '../share/template.js'; const MIN_STATION_NAME_LENGTH = 2; + export default class StationManager extends Component { constructor(props) { super(props); @@ -15,6 +17,7 @@ export default class StationManager extends Component { `#${STATION.STATION_ADD_BUTTON_ID}`, ); this.form = this.container.querySelector(`#${STATION.STATION_FORM_ID}`); + this.table = this.container.querySelector(`#${STATION.STATION_TABLE_BODY}`); this.form.addEventListener('submit', this.onSubmit); } @@ -36,8 +39,22 @@ export default class StationManager extends Component { checkValidity(value) { return ( - checkOverlap(value, this.state.stationList) && - checkValueLength(value, MIN_STATION_NAME_LENGTH) + checkOverlap(value, this.state.stationList) + && checkValueLength(value, MIN_STATION_NAME_LENGTH) ); } + + template() { + return this.state.stationList + .map((station, index) => stationTableTemplate( + station, + index, + STATION.STATION_DELETE_BUTTON_CLASS, + )) + .join(''); + } + + render() { + this.table.innerHTML = this.template(); + } } diff --git a/src/share/template.js b/src/share/template.js new file mode 100644 index 000000000..c632bc24f --- /dev/null +++ b/src/share/template.js @@ -0,0 +1,6 @@ +export const stationTableTemplate = (stationName, index, btnClass) => ` + + ${stationName} + + +`; From a2b9868bfa70e201936325d5914e792890abcdad Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 17:16:20 +0900 Subject: [PATCH 08/44] =?UTF-8?q?[feat]=20=EC=97=AD=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20&=20=EC=82=AD=EC=A0=9C=20=EC=8B=9C=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 삭제 버튼의 data-id와 tr태그의 data-id 를 비교하여 해당 역을 삭제한다. - README.md에 사용자 확인 기능 목록을 추가함. --- README.md | 5 +++-- src/managers/StationManager.js | 20 ++++++++++++++++++-- src/share/template.js | 2 +- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 931b7be12..ad1a05b1b 100644 --- a/README.md +++ b/README.md @@ -139,9 +139,10 @@ - [x] 역 이름이 중복되는지 확인해야한다. - [x] 역 이름이 2글자 이상인지 확인해야 한다 - [x] 사용자가 입력한 역들을 차례대로 출력해야 한다. - - [ ] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. + - [x] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. + - [x] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. + - [ ] 삭제시 사용자의 확인을 받는다 - [ ] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. - - [ ] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. - 노선 관련 기능 diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index dedc4b361..4db09caf3 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -20,15 +20,23 @@ export default class StationManager extends Component { this.table = this.container.querySelector(`#${STATION.STATION_TABLE_BODY}`); this.form.addEventListener('submit', this.onSubmit); + this.table.addEventListener('click', this.onTableClick); } onSubmit = (event) => { event.preventDefault(); const { value } = this.userInput; - this.updateStationList(value); + this.addStationToList(value); }; - updateStationList(station) { + onTableClick = (event) => { + const { className } = event.target; + const { index } = event.target.dataset; + if (className !== STATION.STATION_DELETE_BUTTON_CLASS) return; + this.deleteStationFromList(index); + } + + addStationToList(station) { if (!this.checkValidity(station)) return; const newStationList = [...this.state.stationList]; newStationList.push(station); @@ -37,6 +45,14 @@ export default class StationManager extends Component { }); } + deleteStationFromList(index) { + const newStationList = [...this.state.stationList]; + newStationList.splice(index, 1); + this.setState({ + stationList: newStationList, + }); + } + checkValidity(value) { return ( checkOverlap(value, this.state.stationList) diff --git a/src/share/template.js b/src/share/template.js index c632bc24f..17fb7ff03 100644 --- a/src/share/template.js +++ b/src/share/template.js @@ -1,6 +1,6 @@ export const stationTableTemplate = (stationName, index, btnClass) => ` ${stationName} - + `; From 4fb20e03a7eb39eddaa728b6fd2e6fa526739e9b Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 17:25:03 +0900 Subject: [PATCH 09/44] =?UTF-8?q?[feat]=20=EC=82=AD=EC=A0=9C=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=EC=9E=90=EC=9D=98=20=ED=99=95=EC=9D=B8=EC=9D=84=20=EB=B0=9B?= =?UTF-8?q?=EB=8A=94=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - confirm()함수를 이용하여 사용자의 의사를 확인한다. --- README.md | 2 +- src/managers/StationManager.js | 4 +++- src/share/utils.js | 2 ++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ad1a05b1b..53c3966fb 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ - [x] 사용자가 입력한 역들을 차례대로 출력해야 한다. - [x] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. - [x] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. - - [ ] 삭제시 사용자의 확인을 받는다 + - [x] 삭제시 사용자의 확인을 받는다 - [ ] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. - 노선 관련 기능 diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 4db09caf3..9164ed5c2 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1,9 +1,10 @@ import Component from '../factory/Component.js'; import { STATION } from '../share/selector.js'; -import { checkOverlap, checkValueLength } from '../share/utils.js'; +import { checkOverlap, checkValueLength, customConfirm } from '../share/utils.js'; import { stationTableTemplate } from '../share/template.js'; const MIN_STATION_NAME_LENGTH = 2; +const CONFIRM_MSG = '정말로 삭제하시겠습니까?'; export default class StationManager extends Component { constructor(props) { @@ -33,6 +34,7 @@ export default class StationManager extends Component { const { className } = event.target; const { index } = event.target.dataset; if (className !== STATION.STATION_DELETE_BUTTON_CLASS) return; + if (!customConfirm(CONFIRM_MSG)) return; this.deleteStationFromList(index); } diff --git a/src/share/utils.js b/src/share/utils.js index e64180ba3..579a1afd7 100644 --- a/src/share/utils.js +++ b/src/share/utils.js @@ -1,3 +1,5 @@ export const checkOverlap = (value, list) => !list.includes(value); export const checkValueLength = (value, minLength) => value.length >= minLength; + +export const customConfirm = (message) => confirm(message); From 69284f3428645149cc9f77ebd03608a434ddbf6a Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 17:41:14 +0900 Subject: [PATCH 10/44] =?UTF-8?q?[feat]=20state=EB=A5=BC=20=EA=B3=B5?= =?UTF-8?q?=EC=9C=A0=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 각 메뉴에서 변경된 데이터들을 공유할 수 있도록 함 --- README.md | 1 + src/factory/Component.js | 3 ++- src/index.js | 21 ++++++++++++++++++--- src/managers/LineManager.js | 9 +++++++++ src/managers/StationManager.js | 2 ++ 5 files changed, 32 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 53c3966fb..93a59e03d 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ - 기능 - [x] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) + - [x] state를 공유할 수 있도록 각 메뉴에서 state를 동기화 시킨다. - 역 관련 기능 diff --git a/src/factory/Component.js b/src/factory/Component.js index 0657fa3fc..c62238dd7 100644 --- a/src/factory/Component.js +++ b/src/factory/Component.js @@ -1,6 +1,7 @@ export default class Component { - constructor(props) { + constructor(props = {}) { this.state = {}; + this.props = props; this.managerId = props.managerId; this.container = document.querySelector(`#${props.containerId}`); } diff --git a/src/index.js b/src/index.js index 85c612fa9..9cc9073c4 100644 --- a/src/index.js +++ b/src/index.js @@ -1,29 +1,36 @@ import Component from './factory/Component.js'; -import LineManager from './managers/lineManager.js'; +import LineManager from './managers/LineManager.js'; import MapPrintManager from './managers/MapPrintManager.js'; import SectionManager from './managers/SectionManager.js'; import StationManager from './managers/StationManager.js'; -import { LINE, MAP, MENU, SECTION, STATION } from './share/selector.js'; +import { + LINE, MAP, MENU, SECTION, STATION, +} from './share/selector.js'; -export default class SubwayManager { +export default class SubwayManager extends Component { constructor() { + super(); this.menu = document.querySelector(`#${MENU.MENU_CONTAINER_ID}`); this.stationManager = new StationManager({ managerId: MENU.STATION_MANGER_BUTTON_ID, containerId: STATION.STATION_MANAGER_CONTAINER_ID, + syncData: this.syncData, }); this.lineManager = new LineManager({ managerId: MENU.LINE_MANAGER_BUTTON_ID, containerId: LINE.LINE_MANAGER_CONTAINER_ID, + syncData: this.syncData, }); this.sectionManager = new SectionManager({ managerId: MENU.SECTION_MANAGER_BUTTON_ID, containerId: SECTION.SECTION_MANAGER_CONTAINER_ID, + syncData: this.syncData, }); this.mapPrintManager = new MapPrintManager({ managerId: MENU.MAP_PRINT_MANAGER_BUTTON_ID, containerId: MAP.MAP_PRINT_MANAGER_CONTAINER_ID, + syncData: this.syncData, }); this.menu.addEventListener('click', this.changeMenu); @@ -42,6 +49,14 @@ export default class SubwayManager { manager.managerId === id ? manager.show() : manager.hide(); }); }; + + syncData = (data) => { + this.setState(data); + this.stationManager.setState(data); + this.lineManager.setState(data); + this.sectionManager.setState(data); + this.mapPrintManager.setState(data); + } } new SubwayManager(); diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index b3d22de01..968057d3f 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -1,7 +1,16 @@ import Component from '../factory/Component.js'; +import { LINE } from '../share/selector.js'; export default class LineManager extends Component { constructor(props) { super(props); + + this.form = document.querySelector(`#${LINE.LINE_FORM_ID}`); + this.form.addEventListener('submit', this.handleSubmit); + } + + handleSubmit=(e) => { + e.preventDefault(); + console.log(this.state); } } diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 9164ed5c2..9d906aba6 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -45,6 +45,7 @@ export default class StationManager extends Component { this.setState({ stationList: newStationList, }); + this.props.syncData(this.state); } deleteStationFromList(index) { @@ -53,6 +54,7 @@ export default class StationManager extends Component { this.setState({ stationList: newStationList, }); + this.props.syncData(this.state); } checkValidity(value) { From b0f6ba7c6a1d5f16e7ead09ab52d43f5c51b308f Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 18:16:42 +0900 Subject: [PATCH 11/44] =?UTF-8?q?[feat]=20=EB=85=B8=EC=84=A0=20=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Line class를 이용하여 사용자가 입력한 input의 값들로 새로운 객체 생성 - 역관리 메뉴에서 역 수정시 노선관리 메뉴의 select태그의 옵션들이 변경 될 수 있도록 수정 - lineList 는 state에 저장하여 각 메뉴에서 공유 --- README.md | 4 +-- src/factory/Line.js | 8 ++++++ src/managers/LineManager.js | 50 +++++++++++++++++++++++++++++++++---- src/share/template.js | 2 ++ 4 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 src/factory/Line.js diff --git a/README.md b/README.md index 93a59e03d..1d7ae1068 100644 --- a/README.md +++ b/README.md @@ -147,9 +147,9 @@ - 노선 관련 기능 - - [ ] 노선 이름을 등록 할 수 있게 한다. + - [x] 노선 이름을 등록 할 수 있게 한다. + - [x] 상행 종점 하행 종점을 등록한 역 목록에서 선택할 수 있게 해야한다. - [ ] 노선 이름이 중복되는지 확인해야한다. - - [ ] 상행 종점 하행 종점을 등록한 역 목록에서 선택할 수 있게 해야한다. - [ ] 상행 종점과 하행 종점이 같은지 확인해야 한다. - [ ] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. diff --git a/src/factory/Line.js b/src/factory/Line.js new file mode 100644 index 000000000..a4963158d --- /dev/null +++ b/src/factory/Line.js @@ -0,0 +1,8 @@ +export default class Line { + constructor(props) { + this.name = props.name; + this.startStation = props.startStation; + this.endStation = props.endStation; + this.section = [this.startStation, this.endStation]; + } +} diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 968057d3f..dc2d76eb8 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -1,16 +1,56 @@ import Component from '../factory/Component.js'; +import Line from '../factory/Line.js'; import { LINE } from '../share/selector.js'; +import { optionTemplate } from '../share/template.js'; export default class LineManager extends Component { constructor(props) { super(props); - this.form = document.querySelector(`#${LINE.LINE_FORM_ID}`); - this.form.addEventListener('submit', this.handleSubmit); + this.state.lineList = []; + + this.form = this.container.querySelector(`#${LINE.LINE_FORM_ID}`); + this.userInput = this.container.querySelector(`#${LINE.LINE_NAME_INPUT_ID}`); + this.startStationSelector = this.container.querySelector(`#${LINE.LINE_START_STATION_SELECTOR_ID}`); + this.endStationSelector = this.container.querySelector(`#${LINE.LINE_END_STATION_SELECTOR}`); + this.addBtn = this.container.querySelector(`#${LINE.LINE_ADD_BUTTON_ID}`); + + this.form.addEventListener('submit', this.onSubmit); + } + + updateStationList() { + this.startStationSelector.innerHTML = this.state.stationList.map((station) => optionTemplate(station)).join(''); + this.endStationSelector.innerHTML = this.state.stationList.map((station) => optionTemplate(station)).join(''); + } + + onSubmit = (event) => { + event.preventDefault(); + const constructorObj = this.getValues(); + const newLine = new Line(constructorObj); + this.addLineToList(newLine); + } + + addLineToList(line) { + const newLineList = [...this.state.lineList]; + newLineList.push(line); + this.setState({ + lineList: newLineList, + }); + } + + getValues = () => { + const { value: name } = this.userInput; + const { value: startStation } = this.startStationSelector; + const { value: endStation } = this.endStationSelector; + return { name, startStation, endStation }; } - handleSubmit=(e) => { - e.preventDefault(); - console.log(this.state); + setState(nextData) { + this.state = { + ...this.state, + ...nextData, + }; + this.updateStationList(); + this.render(); } } diff --git a/src/share/template.js b/src/share/template.js index 17fb7ff03..670b14063 100644 --- a/src/share/template.js +++ b/src/share/template.js @@ -4,3 +4,5 @@ export const stationTableTemplate = (stationName, index, btnClass) => ` `; + +export const optionTemplate = (station) => ``; From eabfb06b45d0503cbdc5550edc9d4fce1b6221df Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 20:52:06 +0900 Subject: [PATCH 12/44] =?UTF-8?q?[feat]=20=EB=85=B8=EC=84=A0=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=EC=9D=98=20=EC=A4=91=EB=B3=B5=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 역관리에서 사용한 중복확인 함수를 재활용해 노선이름의 중복을 확인한다. --- README.md | 2 +- src/managers/LineManager.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1d7ae1068..0e91b903d 100644 --- a/README.md +++ b/README.md @@ -149,7 +149,7 @@ - [x] 노선 이름을 등록 할 수 있게 한다. - [x] 상행 종점 하행 종점을 등록한 역 목록에서 선택할 수 있게 해야한다. - - [ ] 노선 이름이 중복되는지 확인해야한다. + - [x] 노선 이름이 중복되는지 확인해야한다. - [ ] 상행 종점과 하행 종점이 같은지 확인해야 한다. - [ ] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index dc2d76eb8..d49318847 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -1,6 +1,7 @@ import Component from '../factory/Component.js'; import Line from '../factory/Line.js'; import { LINE } from '../share/selector.js'; +import { checkOverlap } from '../share/utils.js'; import { optionTemplate } from '../share/template.js'; export default class LineManager extends Component { @@ -31,6 +32,7 @@ export default class LineManager extends Component { } addLineToList(line) { + if (!this.checkValidity(line)) return; const newLineList = [...this.state.lineList]; newLineList.push(line); this.setState({ @@ -38,6 +40,12 @@ export default class LineManager extends Component { }); } + checkValidity=({ name }) => checkOverlap(name, this.getAllLineNames()) + + getAllLineNames() { + return this.state.lineList.map((line) => line.name); + } + getValues = () => { const { value: name } = this.userInput; const { value: startStation } = this.startStationSelector; From 5640e7a03a6aa7cfa02edc26e5ba942ef25f2f85 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 21:04:45 +0900 Subject: [PATCH 13/44] =?UTF-8?q?[feat]=20=EC=83=81=ED=96=89=EC=A2=85?= =?UTF-8?q?=EC=A0=90=EA=B3=BC=20=ED=95=98=ED=96=89=EC=A2=85=EC=A0=90?= =?UTF-8?q?=EC=9D=B4=20=EA=B0=99=EC=9D=80=EC=A7=80=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/managers/LineManager.js | 34 ++++++++++++++++++++++------------ src/share/utils.js | 3 +++ 3 files changed, 26 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 0e91b903d..1d3f40e58 100644 --- a/README.md +++ b/README.md @@ -150,7 +150,7 @@ - [x] 노선 이름을 등록 할 수 있게 한다. - [x] 상행 종점 하행 종점을 등록한 역 목록에서 선택할 수 있게 해야한다. - [x] 노선 이름이 중복되는지 확인해야한다. - - [ ] 상행 종점과 하행 종점이 같은지 확인해야 한다. + - [x] 상행 종점과 하행 종점이 같은지 확인해야 한다. - [ ] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index d49318847..30f040a1a 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -1,7 +1,7 @@ import Component from '../factory/Component.js'; import Line from '../factory/Line.js'; import { LINE } from '../share/selector.js'; -import { checkOverlap } from '../share/utils.js'; +import { checkOverlap, checkSameStation } from '../share/utils.js'; import { optionTemplate } from '../share/template.js'; export default class LineManager extends Component { @@ -11,17 +11,27 @@ export default class LineManager extends Component { this.state.lineList = []; this.form = this.container.querySelector(`#${LINE.LINE_FORM_ID}`); - this.userInput = this.container.querySelector(`#${LINE.LINE_NAME_INPUT_ID}`); - this.startStationSelector = this.container.querySelector(`#${LINE.LINE_START_STATION_SELECTOR_ID}`); - this.endStationSelector = this.container.querySelector(`#${LINE.LINE_END_STATION_SELECTOR}`); + this.userInput = this.container.querySelector( + `#${LINE.LINE_NAME_INPUT_ID}`, + ); + this.startStationSelector = this.container.querySelector( + `#${LINE.LINE_START_STATION_SELECTOR_ID}`, + ); + this.endStationSelector = this.container.querySelector( + `#${LINE.LINE_END_STATION_SELECTOR}`, + ); this.addBtn = this.container.querySelector(`#${LINE.LINE_ADD_BUTTON_ID}`); this.form.addEventListener('submit', this.onSubmit); } updateStationList() { - this.startStationSelector.innerHTML = this.state.stationList.map((station) => optionTemplate(station)).join(''); - this.endStationSelector.innerHTML = this.state.stationList.map((station) => optionTemplate(station)).join(''); + this.startStationSelector.innerHTML = this.state.stationList + .map((station) => optionTemplate(station)) + .join(''); + this.endStationSelector.innerHTML = this.state.stationList + .map((station) => optionTemplate(station)) + .join(''); } onSubmit = (event) => { @@ -29,7 +39,7 @@ export default class LineManager extends Component { const constructorObj = this.getValues(); const newLine = new Line(constructorObj); this.addLineToList(newLine); - } + }; addLineToList(line) { if (!this.checkValidity(line)) return; @@ -40,18 +50,18 @@ export default class LineManager extends Component { }); } - checkValidity=({ name }) => checkOverlap(name, this.getAllLineNames()) + checkValidity = ({ name, startStation, endStation }) => + checkOverlap(name, this.getAllLineNames()) && + checkSameStation(startStation, endStation); - getAllLineNames() { - return this.state.lineList.map((line) => line.name); - } + getAllLineNames = () => this.state.lineList.map((line) => line.name); getValues = () => { const { value: name } = this.userInput; const { value: startStation } = this.startStationSelector; const { value: endStation } = this.endStationSelector; return { name, startStation, endStation }; - } + }; setState(nextData) { this.state = { diff --git a/src/share/utils.js b/src/share/utils.js index 579a1afd7..b64b5a168 100644 --- a/src/share/utils.js +++ b/src/share/utils.js @@ -2,4 +2,7 @@ export const checkOverlap = (value, list) => !list.includes(value); export const checkValueLength = (value, minLength) => value.length >= minLength; +export const checkSameStation = (prevStation, nextStation) => + prevStation !== nextStation; + export const customConfirm = (message) => confirm(message); From 44017f6d31cc0ac4675dc04e2b75773bb355dc4b Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 21:22:07 +0900 Subject: [PATCH 14/44] =?UTF-8?q?[feat]=20=EB=85=B8=EC=84=A0=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=B6=9C=EB=A0=A5=EA=B8=B0=EB=8A=A5=20&=20HTML=20?= =?UTF-8?q?=EC=9E=98=EB=AA=BB=EB=90=9C=20=EB=A7=88=ED=81=AC=EC=97=85?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 노선목록을 templated 업데이트를 통해 출력한다 - 요류를 줄이기 위해 template 에 전달하는 arguments를 객체형로 전달한다. - HTML 잘못된 마크업 수정 --- README.md | 1 + index.html | 1 - src/managers/LineManager.js | 19 ++++++++++++++++++- src/share/template.js | 15 ++++++++++++++- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1d3f40e58..8ab80f436 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ - [x] 상행 종점 하행 종점을 등록한 역 목록에서 선택할 수 있게 해야한다. - [x] 노선 이름이 중복되는지 확인해야한다. - [x] 상행 종점과 하행 종점이 같은지 확인해야 한다. + - [x] 노선목록을 출력한다. - [ ] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. diff --git a/index.html b/index.html index d1e36f366..76387b449 100644 --- a/index.html +++ b/index.html @@ -67,7 +67,6 @@

🚉 지하철 역 목록

-

🚉 지하철 노선 목록

diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 30f040a1a..1ee6bdcb9 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -2,7 +2,7 @@ import Component from '../factory/Component.js'; import Line from '../factory/Line.js'; import { LINE } from '../share/selector.js'; import { checkOverlap, checkSameStation } from '../share/utils.js'; -import { optionTemplate } from '../share/template.js'; +import { lineTableTemplate, optionTemplate } from '../share/template.js'; export default class LineManager extends Component { constructor(props) { @@ -21,6 +21,7 @@ export default class LineManager extends Component { `#${LINE.LINE_END_STATION_SELECTOR}`, ); this.addBtn = this.container.querySelector(`#${LINE.LINE_ADD_BUTTON_ID}`); + this.table = this.container.querySelector(`#${LINE.LINE_TABLE_BODY}`); this.form.addEventListener('submit', this.onSubmit); } @@ -63,6 +64,18 @@ export default class LineManager extends Component { return { name, startStation, endStation }; }; + template() { + return this.state.lineList + .map((line, index) => + lineTableTemplate({ + ...line, + index, + buttonClass: LINE.LINE_DELETE_BUTTON_CLASS, + }), + ) + .join(''); + } + setState(nextData) { this.state = { ...this.state, @@ -71,4 +84,8 @@ export default class LineManager extends Component { this.updateStationList(); this.render(); } + + render() { + this.table.innerHTML = this.template(); + } } diff --git a/src/share/template.js b/src/share/template.js index 670b14063..f20ac9a66 100644 --- a/src/share/template.js +++ b/src/share/template.js @@ -5,4 +5,17 @@ export const stationTableTemplate = (stationName, index, btnClass) => ` `; -export const optionTemplate = (station) => ``; +export const lineTableTemplate = (data) => { + const { name, startStation, endStation, index, buttonClass } = data; + return ` + + + + + + + `; +}; + +export const optionTemplate = (station) => + ``; From 97865bd74293b618fbd62bac448dd21ac7c5d237 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 21:32:04 +0900 Subject: [PATCH 15/44] =?UTF-8?q?[feat]=20=EB=85=B8=EC=84=A0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 역 관리와 같은 방식으로 노선 삭제기능을 추가함 - 노선의 유일한 값을 data프로퍼티를 이용하여 관리함 --- README.md | 5 +++-- src/managers/LineManager.js | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8ab80f436..1eb9a12d9 100644 --- a/README.md +++ b/README.md @@ -152,8 +152,9 @@ - [x] 노선 이름이 중복되는지 확인해야한다. - [x] 상행 종점과 하행 종점이 같은지 확인해야 한다. - [x] 노선목록을 출력한다. - - [ ] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. - - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. + - [x] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. + - [x] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. + - [ ] 삭제 시 사용자의 확인을 받는다. - 구간 관련 기능 diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 1ee6bdcb9..aa9802755 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -24,6 +24,7 @@ export default class LineManager extends Component { this.table = this.container.querySelector(`#${LINE.LINE_TABLE_BODY}`); this.form.addEventListener('submit', this.onSubmit); + this.table.addEventListener('click', this.onTableClick); } updateStationList() { @@ -42,6 +43,13 @@ export default class LineManager extends Component { this.addLineToList(newLine); }; + onTableClick = (event) => { + const { className } = event.target; + const { index } = event.target.dataset; + if (className !== LINE.LINE_DELETE_BUTTON_CLASS) return; + this.deleteLineFromList(index); + }; + addLineToList(line) { if (!this.checkValidity(line)) return; const newLineList = [...this.state.lineList]; @@ -51,6 +59,15 @@ export default class LineManager extends Component { }); } + deleteLineFromList(index) { + const newLineList = [...this.state.lineList]; + newLineList.splice(index, 1); + this.setState({ + lineList: newLineList, + }); + this.props.syncData(this.state); + } + checkValidity = ({ name, startStation, endStation }) => checkOverlap(name, this.getAllLineNames()) && checkSameStation(startStation, endStation); From efa3dc3296326e6451cda16348fd80b1331f06b8 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 21:35:36 +0900 Subject: [PATCH 16/44] =?UTF-8?q?[feat]=20=EB=85=B8=EC=84=A0=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=8B=9C=20=EC=82=AC=EC=9A=A9=EC=9E=90=20=ED=99=95?= =?UTF-8?q?=EC=9D=B8=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - confirm 을 이용하여 노선 삭제시 사용자의 확인을 받는다. --- README.md | 2 +- src/managers/LineManager.js | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1eb9a12d9..5f4e68aa0 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ - [x] 노선목록을 출력한다. - [x] 삭제 버튼 클릭 시 삭제할 수 있게 해야한다. - [x] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. - - [ ] 삭제 시 사용자의 확인을 받는다. + - [x] 삭제 시 사용자의 확인을 받는다. - 구간 관련 기능 diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index aa9802755..4c5dde433 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -1,9 +1,14 @@ import Component from '../factory/Component.js'; import Line from '../factory/Line.js'; import { LINE } from '../share/selector.js'; -import { checkOverlap, checkSameStation } from '../share/utils.js'; +import { + checkOverlap, + checkSameStation, + customConfirm, +} from '../share/utils.js'; import { lineTableTemplate, optionTemplate } from '../share/template.js'; +const CONFIRM_MSG = '정말 노선을 삭제하시겠습니까?'; export default class LineManager extends Component { constructor(props) { super(props); @@ -47,6 +52,7 @@ export default class LineManager extends Component { const { className } = event.target; const { index } = event.target.dataset; if (className !== LINE.LINE_DELETE_BUTTON_CLASS) return; + if (!customConfirm(CONFIRM_MSG)) return; this.deleteLineFromList(index); }; From f42cd23f97b1f7a05db7072b2b91b3b461995f3d Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 21:57:14 +0900 Subject: [PATCH 17/44] =?UTF-8?q?[feat]=20=EB=85=B8=EC=84=A0=EC=97=90=20?= =?UTF-8?q?=ED=8F=AC=ED=95=A8=EB=90=98=EC=96=B4=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=EC=97=AD=EC=9D=80=20=EC=82=AD=EC=A0=9C=20=EB=B6=88=EA=B0=80?= =?UTF-8?q?=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - line데이터를 동기화 하여 역 삭제시 구간에 포함되어있는 모든 역을 조회 하여 포함되어 있는 경우 삭제가 불가능하게 함 --- README.md | 2 +- src/index.js | 12 ++++++++---- src/managers/LineManager.js | 1 + src/managers/StationManager.js | 34 +++++++++++++++++++++++++--------- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 5f4e68aa0..f88adab8a 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ - [x] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. - [x] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. - [x] 삭제시 사용자의 확인을 받는다 - - [ ] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. + - [x] 삭제 시 노선에 추가되어 있을 경우 삭제할 수 없게 해야 한다. - 노선 관련 기능 diff --git a/src/index.js b/src/index.js index 9cc9073c4..de1ecdc39 100644 --- a/src/index.js +++ b/src/index.js @@ -3,13 +3,15 @@ import LineManager from './managers/LineManager.js'; import MapPrintManager from './managers/MapPrintManager.js'; import SectionManager from './managers/SectionManager.js'; import StationManager from './managers/StationManager.js'; -import { - LINE, MAP, MENU, SECTION, STATION, -} from './share/selector.js'; +import { LINE, MAP, MENU, SECTION, STATION } from './share/selector.js'; export default class SubwayManager extends Component { constructor() { super(); + this.state = { + stationList: [], + lineList: [], + }; this.menu = document.querySelector(`#${MENU.MENU_CONTAINER_ID}`); this.stationManager = new StationManager({ @@ -34,6 +36,8 @@ export default class SubwayManager extends Component { }); this.menu.addEventListener('click', this.changeMenu); + + this.syncData(this.state); } changeMenu = (e) => { @@ -56,7 +60,7 @@ export default class SubwayManager extends Component { this.lineManager.setState(data); this.sectionManager.setState(data); this.mapPrintManager.setState(data); - } + }; } new SubwayManager(); diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 4c5dde433..343c757dd 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -63,6 +63,7 @@ export default class LineManager extends Component { this.setState({ lineList: newLineList, }); + this.props.syncData(this.state); } deleteLineFromList(index) { diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 9d906aba6..83328b677 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1,10 +1,15 @@ import Component from '../factory/Component.js'; import { STATION } from '../share/selector.js'; -import { checkOverlap, checkValueLength, customConfirm } from '../share/utils.js'; +import { + checkOverlap, + checkValueLength, + customConfirm, +} from '../share/utils.js'; import { stationTableTemplate } from '../share/template.js'; const MIN_STATION_NAME_LENGTH = 2; const CONFIRM_MSG = '정말로 삭제하시겠습니까?'; +const ALERT_MSG = '노선에 포함되어있어 삭제가 불가능합니다.'; export default class StationManager extends Component { constructor(props) { @@ -33,10 +38,15 @@ export default class StationManager extends Component { onTableClick = (event) => { const { className } = event.target; const { index } = event.target.dataset; + const { name: stationName } = event.target.parentNode.parentNode.dataset; if (className !== STATION.STATION_DELETE_BUTTON_CLASS) return; if (!customConfirm(CONFIRM_MSG)) return; + if (!checkOverlap(stationName, this.getAllStationNamesInLines())) { + alert(ALERT_MSG); + return; + } this.deleteStationFromList(index); - } + }; addStationToList(station) { if (!this.checkValidity(station)) return; @@ -57,20 +67,26 @@ export default class StationManager extends Component { this.props.syncData(this.state); } + getAllStationNamesInLines() { + return [...new Set(this.state.lineList.map((line) => line.section).flat())]; + } + checkValidity(value) { return ( - checkOverlap(value, this.state.stationList) - && checkValueLength(value, MIN_STATION_NAME_LENGTH) + checkOverlap(value, this.state.stationList) && + checkValueLength(value, MIN_STATION_NAME_LENGTH) ); } template() { return this.state.stationList - .map((station, index) => stationTableTemplate( - station, - index, - STATION.STATION_DELETE_BUTTON_CLASS, - )) + .map((station, index) => + stationTableTemplate( + station, + index, + STATION.STATION_DELETE_BUTTON_CLASS, + ), + ) .join(''); } From 4ac7480e50b28e4d9b20c355ce017bf5c36dcccb Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 22:34:04 +0900 Subject: [PATCH 18/44] =?UTF-8?q?[feat]=20=EC=83=88=EB=A1=9C=EA=B3=A0?= =?UTF-8?q?=EC=B9=A8=EC=8B=9C=20=EC=B5=9C=EA=B7=BC=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B6=88=EB=9F=AC=EC=98=A4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - localStorage를 이용하여 새로고침을 하여도 최근 데이터를 불러와 각 메뉴 의 목록들을 표시 한다. - localStorage를에 저장하는 데이터는 JSON을 활용하여 객체로 저장한다. --- README.md | 3 ++- src/index.js | 8 ++++---- src/share/storage.js | 18 ++++++++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 src/share/storage.js diff --git a/README.md b/README.md index f88adab8a..88507119e 100644 --- a/README.md +++ b/README.md @@ -129,10 +129,11 @@ ## 🔥 기능 목록 -- 기능 +- 공통 기능 - [x] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) - [x] state를 공유할 수 있도록 각 메뉴에서 state를 동기화 시킨다. + - [x] localStorage를 이용하여 새로고침해도 최근 데이터를 활용해 목록들을 표시한다. - 역 관련 기능 diff --git a/src/index.js b/src/index.js index de1ecdc39..a5fd41ffe 100644 --- a/src/index.js +++ b/src/index.js @@ -4,14 +4,13 @@ import MapPrintManager from './managers/MapPrintManager.js'; import SectionManager from './managers/SectionManager.js'; import StationManager from './managers/StationManager.js'; import { LINE, MAP, MENU, SECTION, STATION } from './share/selector.js'; +import storage from './share/storage.js'; +const STORAGE_KEY = 'state'; export default class SubwayManager extends Component { constructor() { super(); - this.state = { - stationList: [], - lineList: [], - }; + this.state = storage.getItem(STORAGE_KEY); this.menu = document.querySelector(`#${MENU.MENU_CONTAINER_ID}`); this.stationManager = new StationManager({ @@ -55,6 +54,7 @@ export default class SubwayManager extends Component { }; syncData = (data) => { + storage.setItem(STORAGE_KEY, data); this.setState(data); this.stationManager.setState(data); this.lineManager.setState(data); diff --git a/src/share/storage.js b/src/share/storage.js new file mode 100644 index 000000000..a632ac251 --- /dev/null +++ b/src/share/storage.js @@ -0,0 +1,18 @@ +const defaultState = { + stationList: [], + lineList: [], +}; + +const setItem = (key, data) => localStorage.setItem(key, JSON.stringify(data)); + +const getItem = (key) => { + const data = JSON.parse(localStorage.getItem(key)); + return data || defaultState; +}; + +const storage = { + setItem, + getItem, +}; + +export default storage; From 6619044951575c60ee29572752ada081039be0b4 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 22:47:27 +0900 Subject: [PATCH 19/44] =?UTF-8?q?[style]=20=EC=83=81=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - selector에서 공통되는 부분을 줄이고 이해하기 쉽게 변경함 ex) LINE.LINE_CONTAINER_ID => LINE_SELECTOR.CONTAINER_ID - 축약했던 변수명을 축약하지 않음 ex) btn => button --- src/index.js | 16 +++++--- src/managers/LineManager.js | 24 ++++++------ src/managers/StationManager.js | 26 ++++++------ src/share/selector.js | 72 +++++++++++++++++----------------- src/share/template.js | 4 +- 5 files changed, 76 insertions(+), 66 deletions(-) diff --git a/src/index.js b/src/index.js index a5fd41ffe..696126cdb 100644 --- a/src/index.js +++ b/src/index.js @@ -3,7 +3,13 @@ import LineManager from './managers/LineManager.js'; import MapPrintManager from './managers/MapPrintManager.js'; import SectionManager from './managers/SectionManager.js'; import StationManager from './managers/StationManager.js'; -import { LINE, MAP, MENU, SECTION, STATION } from './share/selector.js'; +import { + MENU, + STATION_SELECTOR, + LINE_SELECTOR, + SECTION_SELECTOR, + MAP_SELECTOR, +} from './share/selector.js'; import storage from './share/storage.js'; const STORAGE_KEY = 'state'; @@ -15,22 +21,22 @@ export default class SubwayManager extends Component { this.stationManager = new StationManager({ managerId: MENU.STATION_MANGER_BUTTON_ID, - containerId: STATION.STATION_MANAGER_CONTAINER_ID, + containerId: STATION_SELECTOR.MANAGER_CONTAINER_ID, syncData: this.syncData, }); this.lineManager = new LineManager({ managerId: MENU.LINE_MANAGER_BUTTON_ID, - containerId: LINE.LINE_MANAGER_CONTAINER_ID, + containerId: LINE_SELECTOR.MANAGER_CONTAINER_ID, syncData: this.syncData, }); this.sectionManager = new SectionManager({ managerId: MENU.SECTION_MANAGER_BUTTON_ID, - containerId: SECTION.SECTION_MANAGER_CONTAINER_ID, + containerId: SECTION_SELECTOR.MANAGER_CONTAINER_ID, syncData: this.syncData, }); this.mapPrintManager = new MapPrintManager({ managerId: MENU.MAP_PRINT_MANAGER_BUTTON_ID, - containerId: MAP.MAP_PRINT_MANAGER_CONTAINER_ID, + containerId: MAP_SELECTOR.PRINT_MANAGER_CONTAINER_ID, syncData: this.syncData, }); diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 343c757dd..7fbcada63 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -1,6 +1,6 @@ import Component from '../factory/Component.js'; import Line from '../factory/Line.js'; -import { LINE } from '../share/selector.js'; +import { LINE_SELECTOR } from '../share/selector.js'; import { checkOverlap, checkSameStation, @@ -8,25 +8,27 @@ import { } from '../share/utils.js'; import { lineTableTemplate, optionTemplate } from '../share/template.js'; -const CONFIRM_MSG = '정말 노선을 삭제하시겠습니까?'; +const CONFIRM_MESSAGE = '정말 노선을 삭제하시겠습니까?'; export default class LineManager extends Component { constructor(props) { super(props); this.state.lineList = []; - this.form = this.container.querySelector(`#${LINE.LINE_FORM_ID}`); + this.form = this.container.querySelector(`#${LINE_SELECTOR.FORM_ID}`); this.userInput = this.container.querySelector( - `#${LINE.LINE_NAME_INPUT_ID}`, + `#${LINE_SELECTOR.NAME_INPUT_ID}`, ); this.startStationSelector = this.container.querySelector( - `#${LINE.LINE_START_STATION_SELECTOR_ID}`, + `#${LINE_SELECTOR.START_STATION_SELECTOR_ID}`, ); this.endStationSelector = this.container.querySelector( - `#${LINE.LINE_END_STATION_SELECTOR}`, + `#${LINE_SELECTOR.END_STATION_SELECTOR}`, ); - this.addBtn = this.container.querySelector(`#${LINE.LINE_ADD_BUTTON_ID}`); - this.table = this.container.querySelector(`#${LINE.LINE_TABLE_BODY}`); + this.addButton = this.container.querySelector( + `#${LINE_SELECTOR.ADD_BUTTON_ID}`, + ); + this.table = this.container.querySelector(`#${LINE_SELECTOR.TABLE_BODY}`); this.form.addEventListener('submit', this.onSubmit); this.table.addEventListener('click', this.onTableClick); @@ -51,8 +53,8 @@ export default class LineManager extends Component { onTableClick = (event) => { const { className } = event.target; const { index } = event.target.dataset; - if (className !== LINE.LINE_DELETE_BUTTON_CLASS) return; - if (!customConfirm(CONFIRM_MSG)) return; + if (className !== LINE_SELECTOR.DELETE_BUTTON_CLASS) return; + if (!customConfirm(CONFIRM_MESSAGE)) return; this.deleteLineFromList(index); }; @@ -94,7 +96,7 @@ export default class LineManager extends Component { lineTableTemplate({ ...line, index, - buttonClass: LINE.LINE_DELETE_BUTTON_CLASS, + buttonClass: LINE_SELECTOR.DELETE_BUTTON_CLASS, }), ) .join(''); diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 83328b677..c7674f53a 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1,5 +1,5 @@ import Component from '../factory/Component.js'; -import { STATION } from '../share/selector.js'; +import { STATION_SELECTOR } from '../share/selector.js'; import { checkOverlap, checkValueLength, @@ -8,8 +8,8 @@ import { import { stationTableTemplate } from '../share/template.js'; const MIN_STATION_NAME_LENGTH = 2; -const CONFIRM_MSG = '정말로 삭제하시겠습니까?'; -const ALERT_MSG = '노선에 포함되어있어 삭제가 불가능합니다.'; +const CONFIRM_MESSAGE = '정말로 삭제하시겠습니까?'; +const ALERT_MESSAGE = '노선에 포함되어있어 삭제가 불가능합니다.'; export default class StationManager extends Component { constructor(props) { @@ -17,13 +17,15 @@ export default class StationManager extends Component { this.state.stationList = []; this.userInput = this.container.querySelector( - `#${STATION.STATION_NAME_INPUT_ID}`, + `#${STATION_SELECTOR.NAME_INPUT_ID}`, ); - this.addBtn = this.container.querySelector( - `#${STATION.STATION_ADD_BUTTON_ID}`, + this.addButton = this.container.querySelector( + `#${STATION_SELECTOR.ADD_BUTTON_ID}`, + ); + this.form = this.container.querySelector(`#${STATION_SELECTOR.FORM_ID}`); + this.table = this.container.querySelector( + `#${STATION_SELECTOR.TABLE_BODY}`, ); - this.form = this.container.querySelector(`#${STATION.STATION_FORM_ID}`); - this.table = this.container.querySelector(`#${STATION.STATION_TABLE_BODY}`); this.form.addEventListener('submit', this.onSubmit); this.table.addEventListener('click', this.onTableClick); @@ -39,10 +41,10 @@ export default class StationManager extends Component { const { className } = event.target; const { index } = event.target.dataset; const { name: stationName } = event.target.parentNode.parentNode.dataset; - if (className !== STATION.STATION_DELETE_BUTTON_CLASS) return; - if (!customConfirm(CONFIRM_MSG)) return; + if (className !== STATION_SELECTOR.DELETE_BUTTON_CLASS) return; + if (!customConfirm(CONFIRM_MESSAGE)) return; if (!checkOverlap(stationName, this.getAllStationNamesInLines())) { - alert(ALERT_MSG); + alert(ALERT_MESSAGE); return; } this.deleteStationFromList(index); @@ -84,7 +86,7 @@ export default class StationManager extends Component { stationTableTemplate( station, index, - STATION.STATION_DELETE_BUTTON_CLASS, + STATION_SELECTOR.DELETE_BUTTON_CLASS, ), ) .join(''); diff --git a/src/share/selector.js b/src/share/selector.js index c4e83d1ae..bfbfecd09 100644 --- a/src/share/selector.js +++ b/src/share/selector.js @@ -6,47 +6,47 @@ export const MENU = Object.freeze({ MAP_PRINT_MANAGER_BUTTON_ID: 'map-print-manager-button', }); -export const STATION = Object.freeze({ - STATION_MANAGER_CONTAINER_ID: 'station-manager', - STATION_FORM_ID: 'station-form', - STATION_RESULT_CONTAINER_ID: 'station-result', - STATION_TABLE: 'station-table', - STATION_TABLE_BODY: 'station-table-body', - STATION_NAME_INPUT_ID: 'station-name-input', - STATION_ADD_BUTTON_ID: 'station-add-button', - STATION_DELETE_BUTTON_CLASS: 'station-delete-button', +export const STATION_SELECTOR = Object.freeze({ + MANAGER_CONTAINER_ID: 'station-manager', + FORM_ID: 'station-form', + RESULT_CONTAINER_ID: 'station-result', + TABLE: 'station-table', + TABLE_BODY: 'station-table-body', + NAME_INPUT_ID: 'station-name-input', + ADD_BUTTON_ID: 'station-add-button', + DELETE_BUTTON_CLASS: 'station-delete-button', }); -export const LINE = Object.freeze({ - LINE_MANAGER_CONTAINER_ID: 'line-manager', - LINE_FORM_ID: 'line-form', - LINE_NAME_INPUT_ID: 'line-name-input', - LINE_START_STATION_SELECTOR_ID: 'line-start-station-selector', - LINE_END_STATION_SELECTOR: 'line-end-station-selector', - LINE_ADD_BUTTON_ID: 'line-add-button', - LINE_DELETE_BUTTON_CLASS: 'line-delete-button', - LINE_RESULT_CONTAINER_ID: 'line-result', - LINE_TABLE: 'line-table', - LINE_TABLE_BODY: 'line-table-body', +export const LINE_SELECTOR = Object.freeze({ + MANAGER_CONTAINER_ID: 'line-manager', + FORM_ID: 'line-form', + NAME_INPUT_ID: 'line-name-input', + START_STATION_SELECTOR_ID: 'line-start-station-selector', + END_STATION_SELECTOR: 'line-end-station-selector', + ADD_BUTTON_ID: 'line-add-button', + DELETE_BUTTON_CLASS: 'line-delete-button', + RESULT_CONTAINER_ID: 'line-result', + TABLE: 'line-table', + TABLE_BODY: 'line-table-body', }); -export const SECTION = Object.freeze({ - SECTION_MANAGER_CONTAINER_ID: 'section-manager', - SECTION_LINE_MENU_ID: 'section-line-menu', - SECTION_LINE_MENU_BUTTON_CLASS: 'section-line-menu-button', - SECTION_DETAIL_CONTAINER_ID: 'section-detail', - SECTION_FORM_ID: 'section-form', - SECTION_FORM_HEADER_ID: 'section-form-header', - SECTION_STATION_SELECTOR_ID: 'section-station-selector', - SECTION_ORDER_INPUT_ID: 'section-order-input', - SECTION_ADD_BUTTON_ID: 'section-add-button', - SECTION_DELETE_BUTTON: 'section-delete-button', - SECTION_RESULT_CONTAINER_ID: 'section-result', - SECTION_TABLE: 'section-table', - SECTION_TABLE_BODY: 'section-table-body', +export const SECTION_SELECTOR = Object.freeze({ + MANAGER_CONTAINER_ID: 'section-manager', + LINE_MENU_ID: 'section-line-menu', + LINE_MENU_BUTTON_CLASS: 'section-line-menu-button', + DETAIL_CONTAINER_ID: 'section-detail', + FORM_ID: 'section-form', + FORM_HEADER_ID: 'section-form-header', + STATION_SELECTOR_ID: 'section-station-selector', + ORDER_INPUT_ID: 'section-order-input', + ADD_BUTTON_ID: 'section-add-button', + DELETE_BUTTON: 'section-delete-button', + RESULT_CONTAINER_ID: 'section-result', + TABLE: 'section-table', + TABLE_BODY: 'section-table-body', }); -export const MAP = Object.freeze({ - MAP_PRINT_MANAGER_CONTAINER_ID: 'map-print-manager', +export const MAP_SELECTOR = Object.freeze({ + PRINT_MANAGER_CONTAINER_ID: 'map-print-manager', MAP_CLASS: 'map', }); diff --git a/src/share/template.js b/src/share/template.js index f20ac9a66..e93a6568c 100644 --- a/src/share/template.js +++ b/src/share/template.js @@ -1,7 +1,7 @@ -export const stationTableTemplate = (stationName, index, btnClass) => ` +export const stationTableTemplate = (stationName, index, buttonClass) => ` - + `; From 6575663abc314c1b6541a3418d1539f984d1bab8 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 22:57:17 +0900 Subject: [PATCH 20/44] =?UTF-8?q?[feat]=20form=20=EC=A0=9C=EC=B6=9C?= =?UTF-8?q?=EC=8B=9C=20input=20=EC=98=81=EC=97=AD=20=EC=B4=88=EA=B8=B0?= =?UTF-8?q?=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + src/managers/LineManager.js | 5 +++++ src/managers/StationManager.js | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/README.md b/README.md index 88507119e..9823321fb 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ - [x] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) - [x] state를 공유할 수 있도록 각 메뉴에서 state를 동기화 시킨다. - [x] localStorage를 이용하여 새로고침해도 최근 데이터를 활용해 목록들을 표시한다. + - [x] form 제출이 input을 초기화 한다. - 역 관련 기능 diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 7fbcada63..4e4fee5e2 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -48,6 +48,7 @@ export default class LineManager extends Component { const constructorObj = this.getValues(); const newLine = new Line(constructorObj); this.addLineToList(newLine); + this.clearInput(); }; onTableClick = (event) => { @@ -90,6 +91,10 @@ export default class LineManager extends Component { return { name, startStation, endStation }; }; + clearInput() { + this.userInput.value = ''; + } + template() { return this.state.lineList .map((line, index) => diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index c7674f53a..59f7b7a37 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -35,6 +35,7 @@ export default class StationManager extends Component { event.preventDefault(); const { value } = this.userInput; this.addStationToList(value); + this.clearInput(); }; onTableClick = (event) => { @@ -80,6 +81,10 @@ export default class StationManager extends Component { ); } + clearInput() { + this.userInput.value = ''; + } + template() { return this.state.stationList .map((station, index) => From 1973220600e3c497b1c1c2518228cc2e4eba1bc9 Mon Sep 17 00:00:00 2001 From: nxxc Date: Mon, 14 Dec 2020 23:14:10 +0900 Subject: [PATCH 21/44] =?UTF-8?q?[feat]=20=EC=82=AC=EC=9A=A9=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EB=93=B1=EB=A1=9D=ED=95=9C=20=EB=85=B8=EC=84=A0?= =?UTF-8?q?=EC=9D=84=20=EB=B2=84=ED=8A=BC=EC=9C=BC=EB=A1=9C=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 구간 관리 메뉴 선택시 사용자가 등록한 노선을 선택할 수 있도록 표시함. --- README.md | 2 +- src/managers/SectionDetailManager.js | 7 +++++++ src/managers/SectionManager.js | 22 ++++++++++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 src/managers/SectionDetailManager.js diff --git a/README.md b/README.md index 9823321fb..ac7af18d5 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ - 구간 관련 기능 - - [ ] 사용자가 등록한 노선을 표시해야한다. + - [x] 사용자가 등록한 노선을 표시해야한다. - [ ] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. - [ ] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js new file mode 100644 index 000000000..d286ddf3f --- /dev/null +++ b/src/managers/SectionDetailManager.js @@ -0,0 +1,7 @@ +import Component from '../factory/Component.js'; + +export default class SectionDetailManager extends Component { + constructor(props) { + super(props); + } +} diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index e21f05d1a..365b3384b 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -1,7 +1,29 @@ import Component from '../factory/Component.js'; +import { SECTION_SELECTOR } from '../share/selector.js'; +import SectionDetailManager from './SectionDetailManager.js'; export default class SectionManager extends Component { constructor(props) { super(props); + + this.sectionLineMenu = this.container.querySelector( + `#${SECTION_SELECTOR.LINE_MENU_ID}`, + ); + this.sectionDetailManager = new SectionDetailManager({ + containerId: SECTION_SELECTOR.DETAIL_CONTAINER_ID, + syncData: this.props.syncData, + }); + + this.sectionDetailManager.hide(); + } + + template() { + return this.state.lineList + .map((line) => ``) + .join(''); + } + + render() { + this.sectionLineMenu.innerHTML = this.template(); } } From 67ba272b7b4748ec86603be577e46e93802642df Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 00:05:28 +0900 Subject: [PATCH 22/44] =?UTF-8?q?[feat]=20=EB=85=B8=EC=84=A0=20=ED=81=B4?= =?UTF-8?q?=EB=A6=AD=EC=8B=9C=20=ED=95=B4=EB=8B=B9=20=EB=85=B8=EC=84=A0?= =?UTF-8?q?=EC=9D=84=20=EC=88=98=EC=A0=95=ED=95=A0=20=EC=88=98=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - storage에서 초기 data의 형태를 정할 수 있게함 - 노선 클릭시 해당하는 노선의 데이터를 활용 할 수 있게 함 --- README.md | 2 +- index.html | 2 +- src/index.js | 1 + src/managers/SectionDetailManager.js | 59 ++++++++++++++++++++++++++++ src/managers/SectionManager.js | 18 ++++++++- src/share/storage.js | 4 ++ src/share/template.js | 11 ++++++ 7 files changed, 94 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ac7af18d5..78b9b5a65 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ - 구간 관련 기능 - [x] 사용자가 등록한 노선을 표시해야한다. - - [ ] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. + - [x] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. - [ ] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. diff --git a/index.html b/index.html index 76387b449..2feab0924 100644 --- a/index.html +++ b/index.html @@ -95,7 +95,7 @@

구간 등록

diff --git a/src/index.js b/src/index.js index 696126cdb..2a32f449c 100644 --- a/src/index.js +++ b/src/index.js @@ -65,6 +65,7 @@ export default class SubwayManager extends Component { this.stationManager.setState(data); this.lineManager.setState(data); this.sectionManager.setState(data); + this.sectionManager.sectionDetailManager.setState(data); this.mapPrintManager.setState(data); }; } diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index d286ddf3f..abf287392 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -1,7 +1,66 @@ import Component from '../factory/Component.js'; +import { SECTION_SELECTOR } from '../share/selector.js'; +import { + optionTemplate, + sectionDetailTableTemplate, +} from '../share/template.js'; export default class SectionDetailManager extends Component { constructor(props) { super(props); + + this.form = this.container.querySelector(`#${SECTION_SELECTOR.FORM_ID}`); + this.formHeader = this.container.querySelector( + `#${SECTION_SELECTOR.FORM_HEADER_ID}`, + ); + this.stationSelector = this.container.querySelector( + `#${SECTION_SELECTOR.STATION_SELECTOR_ID}`, + ); + this.orderInput = this.container.querySelector( + `#${SECTION_SELECTOR.ORDER_INPUT_ID}`, + ); + this.addButton = this.container.querySelector( + `#${SECTION_SELECTOR.ADD_BUTTON_ID}`, + ); + this.table = this.container.querySelector( + `#${SECTION_SELECTOR.TABLE_BODY}`, + ); + } + + updateOptions() { + this.stationSelector.innerHTML = this.state.stationList + .map((station) => optionTemplate(station)) + .join(''); + } + + setState(nextData) { + this.state = { + ...this.state, + ...nextData, + }; + this.updateOptions(); + this.render(); + } + + updateFormHeader() { + const { name } = this.state.currentLineData; + this.formHeader.innerHTML = `${name} 관리`; + } + + updateTableBody() { + this.table.innerHTML = this.state.currentLineData.section + .map((station, index) => + sectionDetailTableTemplate({ + name: station, + index, + buttonClass: SECTION_SELECTOR.DELETE_BUTTON, + }), + ) + .join(''); + } + + render() { + this.updateFormHeader(); + this.updateTableBody(); } } diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index 365b3384b..2fe6666cd 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -14,12 +14,28 @@ export default class SectionManager extends Component { syncData: this.props.syncData, }); + this.sectionLineMenu.addEventListener( + 'click', + this.changeSectionDetailManger, + ); + this.sectionDetailManager.hide(); } + changeSectionDetailManger = (e) => { + const { name: selectedLineName } = e.target.dataset; + this.sectionDetailManager.setState({ + currentLineData: this.getSelectedLine(selectedLineName), + }); + this.sectionDetailManager.show(); + }; + + getSelectedLine = (name) => + this.state.lineList.find((line) => line.name === name); + template() { return this.state.lineList - .map((line) => ``) + .map((line) => ``) .join(''); } diff --git a/src/share/storage.js b/src/share/storage.js index a632ac251..b5a059f34 100644 --- a/src/share/storage.js +++ b/src/share/storage.js @@ -1,6 +1,10 @@ const defaultState = { stationList: [], lineList: [], + currentLineData: { + name: '', + section: [], + }, }; const setItem = (key, data) => localStorage.setItem(key, JSON.stringify(data)); diff --git a/src/share/template.js b/src/share/template.js index e93a6568c..cd57b8025 100644 --- a/src/share/template.js +++ b/src/share/template.js @@ -17,5 +17,16 @@ export const lineTableTemplate = (data) => { `; }; +export const sectionDetailTableTemplate = (data) => { + const { index, name, buttonClass } = data; + return ` +
+ + + + + `; +}; + export const optionTemplate = (station) => ``; From 5b822d3c5ee351478ce10bec7490cf5a707f3c15 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 00:12:01 +0900 Subject: [PATCH 23/44] =?UTF-8?q?[style]=20state=20=3D>=20data=20=EB=B3=80?= =?UTF-8?q?=EC=88=98=EB=AA=85=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - state보다 data의 의미가 명확하기때문에 변경함 --- src/factory/Component.js | 8 ++++---- src/index.js | 18 +++++++++--------- src/managers/LineManager.js | 28 ++++++++++++++-------------- src/managers/SectionDetailManager.js | 12 ++++++------ src/managers/SectionManager.js | 6 +++--- src/managers/StationManager.js | 20 ++++++++++---------- 6 files changed, 46 insertions(+), 46 deletions(-) diff --git a/src/factory/Component.js b/src/factory/Component.js index c62238dd7..164f0e18b 100644 --- a/src/factory/Component.js +++ b/src/factory/Component.js @@ -1,14 +1,14 @@ export default class Component { constructor(props = {}) { - this.state = {}; + this.data = {}; this.props = props; this.managerId = props.managerId; this.container = document.querySelector(`#${props.containerId}`); } - setState(nextData) { - this.state = { - ...this.state, + setData(nextData) { + this.data = { + ...this.data, ...nextData, }; this.render(); diff --git a/src/index.js b/src/index.js index 2a32f449c..6f05beae8 100644 --- a/src/index.js +++ b/src/index.js @@ -12,11 +12,11 @@ import { } from './share/selector.js'; import storage from './share/storage.js'; -const STORAGE_KEY = 'state'; +const STORAGE_KEY = 'data'; export default class SubwayManager extends Component { constructor() { super(); - this.state = storage.getItem(STORAGE_KEY); + this.data = storage.getItem(STORAGE_KEY); this.menu = document.querySelector(`#${MENU.MENU_CONTAINER_ID}`); this.stationManager = new StationManager({ @@ -42,7 +42,7 @@ export default class SubwayManager extends Component { this.menu.addEventListener('click', this.changeMenu); - this.syncData(this.state); + this.syncData(this.data); } changeMenu = (e) => { @@ -61,12 +61,12 @@ export default class SubwayManager extends Component { syncData = (data) => { storage.setItem(STORAGE_KEY, data); - this.setState(data); - this.stationManager.setState(data); - this.lineManager.setState(data); - this.sectionManager.setState(data); - this.sectionManager.sectionDetailManager.setState(data); - this.mapPrintManager.setState(data); + this.setData(data); + this.stationManager.setData(data); + this.lineManager.setData(data); + this.sectionManager.setData(data); + this.sectionManager.sectionDetailManager.setData(data); + this.mapPrintManager.setData(data); }; } diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 4e4fee5e2..c8993419e 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -13,7 +13,7 @@ export default class LineManager extends Component { constructor(props) { super(props); - this.state.lineList = []; + this.data.lineList = []; this.form = this.container.querySelector(`#${LINE_SELECTOR.FORM_ID}`); this.userInput = this.container.querySelector( @@ -35,10 +35,10 @@ export default class LineManager extends Component { } updateStationList() { - this.startStationSelector.innerHTML = this.state.stationList + this.startStationSelector.innerHTML = this.data.stationList .map((station) => optionTemplate(station)) .join(''); - this.endStationSelector.innerHTML = this.state.stationList + this.endStationSelector.innerHTML = this.data.stationList .map((station) => optionTemplate(station)) .join(''); } @@ -61,28 +61,28 @@ export default class LineManager extends Component { addLineToList(line) { if (!this.checkValidity(line)) return; - const newLineList = [...this.state.lineList]; + const newLineList = [...this.data.lineList]; newLineList.push(line); - this.setState({ + this.setData({ lineList: newLineList, }); - this.props.syncData(this.state); + this.props.syncData(this.data); } deleteLineFromList(index) { - const newLineList = [...this.state.lineList]; + const newLineList = [...this.data.lineList]; newLineList.splice(index, 1); - this.setState({ + this.setData({ lineList: newLineList, }); - this.props.syncData(this.state); + this.props.syncData(this.data); } checkValidity = ({ name, startStation, endStation }) => checkOverlap(name, this.getAllLineNames()) && checkSameStation(startStation, endStation); - getAllLineNames = () => this.state.lineList.map((line) => line.name); + getAllLineNames = () => this.data.lineList.map((line) => line.name); getValues = () => { const { value: name } = this.userInput; @@ -96,7 +96,7 @@ export default class LineManager extends Component { } template() { - return this.state.lineList + return this.data.lineList .map((line, index) => lineTableTemplate({ ...line, @@ -107,9 +107,9 @@ export default class LineManager extends Component { .join(''); } - setState(nextData) { - this.state = { - ...this.state, + setData(nextData) { + this.data = { + ...this.data, ...nextData, }; this.updateStationList(); diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index abf287392..79d04ac0b 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -28,14 +28,14 @@ export default class SectionDetailManager extends Component { } updateOptions() { - this.stationSelector.innerHTML = this.state.stationList + this.stationSelector.innerHTML = this.data.stationList .map((station) => optionTemplate(station)) .join(''); } - setState(nextData) { - this.state = { - ...this.state, + setData(nextData) { + this.data = { + ...this.data, ...nextData, }; this.updateOptions(); @@ -43,12 +43,12 @@ export default class SectionDetailManager extends Component { } updateFormHeader() { - const { name } = this.state.currentLineData; + const { name } = this.data.currentLineData; this.formHeader.innerHTML = `${name} 관리`; } updateTableBody() { - this.table.innerHTML = this.state.currentLineData.section + this.table.innerHTML = this.data.currentLineData.section .map((station, index) => sectionDetailTableTemplate({ name: station, diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index 2fe6666cd..7ea99101c 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -24,17 +24,17 @@ export default class SectionManager extends Component { changeSectionDetailManger = (e) => { const { name: selectedLineName } = e.target.dataset; - this.sectionDetailManager.setState({ + this.sectionDetailManager.setData({ currentLineData: this.getSelectedLine(selectedLineName), }); this.sectionDetailManager.show(); }; getSelectedLine = (name) => - this.state.lineList.find((line) => line.name === name); + this.data.lineList.find((line) => line.name === name); template() { - return this.state.lineList + return this.data.lineList .map((line) => ``) .join(''); } diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 59f7b7a37..672677fc4 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -14,7 +14,7 @@ const ALERT_MESSAGE = '노선에 포함되어있어 삭제가 불가능합니다 export default class StationManager extends Component { constructor(props) { super(props); - this.state.stationList = []; + this.data.stationList = []; this.userInput = this.container.querySelector( `#${STATION_SELECTOR.NAME_INPUT_ID}`, @@ -53,30 +53,30 @@ export default class StationManager extends Component { addStationToList(station) { if (!this.checkValidity(station)) return; - const newStationList = [...this.state.stationList]; + const newStationList = [...this.data.stationList]; newStationList.push(station); - this.setState({ + this.setData({ stationList: newStationList, }); - this.props.syncData(this.state); + this.props.syncData(this.data); } deleteStationFromList(index) { - const newStationList = [...this.state.stationList]; + const newStationList = [...this.data.stationList]; newStationList.splice(index, 1); - this.setState({ + this.setData({ stationList: newStationList, }); - this.props.syncData(this.state); + this.props.syncData(this.data); } getAllStationNamesInLines() { - return [...new Set(this.state.lineList.map((line) => line.section).flat())]; + return [...new Set(this.data.lineList.map((line) => line.section).flat())]; } checkValidity(value) { return ( - checkOverlap(value, this.state.stationList) && + checkOverlap(value, this.data.stationList) && checkValueLength(value, MIN_STATION_NAME_LENGTH) ); } @@ -86,7 +86,7 @@ export default class StationManager extends Component { } template() { - return this.state.stationList + return this.data.stationList .map((station, index) => stationTableTemplate( station, From 4266f98cf907b72f42b52ac42c20642b43f735bf Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 00:16:43 +0900 Subject: [PATCH 24/44] =?UTF-8?q?[bug]=20=EA=B5=AC=EA=B0=84=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=EC=97=90=EC=84=9C=20=EB=85=B8=EC=84=A0=EC=9D=B4?= =?UTF-8?q?=EC=99=B8=20=ED=81=B4=EB=A6=AD=EC=8B=9C=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=20=EB=B0=9C=EC=83=9D=20=EB=A7=89=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 구간관리에서 노선버튼 이외의 곳을 눌러도 이벤트가 발생하던 버그 수정 - e => event 로 변수명 변경 --- src/index.js | 6 +++--- src/managers/SectionManager.js | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/index.js b/src/index.js index 6f05beae8..1639c880b 100644 --- a/src/index.js +++ b/src/index.js @@ -45,9 +45,9 @@ export default class SubwayManager extends Component { this.syncData(this.data); } - changeMenu = (e) => { - const { nodeName } = e.target; - const { id } = e.target; + changeMenu = (event) => { + const { nodeName } = event.target; + const { id } = event.target; if (nodeName !== 'BUTTON') return; [ this.stationManager, diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index 7ea99101c..0ef87f05b 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -22,8 +22,9 @@ export default class SectionManager extends Component { this.sectionDetailManager.hide(); } - changeSectionDetailManger = (e) => { - const { name: selectedLineName } = e.target.dataset; + changeSectionDetailManger = (event) => { + if (event.target.nodeName !== 'BUTTON') return; + const { name: selectedLineName } = event.target.dataset; this.sectionDetailManager.setData({ currentLineData: this.getSelectedLine(selectedLineName), }); From 8f71bebba2c3eab1490091371d5b08eb3eb3e031 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 11:15:29 +0900 Subject: [PATCH 25/44] =?UTF-8?q?[fix]=20=EC=83=88=EB=A1=9C=EA=B3=A0?= =?UTF-8?q?=EC=B9=A8=20=EC=8B=9C=20Line=20=EC=83=9D=EC=84=B1=EC=9E=90?= =?UTF-8?q?=EA=B0=80=20=EC=97=86=EC=96=B4=EC=A7=80=EB=8D=98=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - localStorage 에 저장된 객체는 생성자까지 저장되지 않는다 따라서 새로고 침시에 localStorage에 저장된 데이터를 불러올 때 미들웨어를 통해 lineList 의 정보들을 새로운 생성자를 호출함으로써 새로운 인스턴스들로 데이터를 반 환하여 메서드들을 사용할 수 있도록 하였다 --- src/share/storage.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/share/storage.js b/src/share/storage.js index b5a059f34..15a3c694e 100644 --- a/src/share/storage.js +++ b/src/share/storage.js @@ -1,3 +1,5 @@ +import Line from '../factory/Line.js'; + const defaultState = { stationList: [], lineList: [], @@ -7,10 +9,14 @@ const defaultState = { }, }; +const jsonToClassConverter = (dataList, Creator) => + dataList.map((data) => new Creator(data)); + const setItem = (key, data) => localStorage.setItem(key, JSON.stringify(data)); const getItem = (key) => { const data = JSON.parse(localStorage.getItem(key)); + data.lineList = jsonToClassConverter(data.lineList, Line); return data || defaultState; }; From f0dd0c9ae819d6b90ea2d5c751c2883e37802bd9 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 11:23:14 +0900 Subject: [PATCH 26/44] =?UTF-8?q?[feat]=20=EA=B5=AC=EA=B0=84=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=20=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 사용자가 입력한 구간을 등록하고 목록을 갱신하여 보여준다. --- README.md | 3 ++- src/factory/Line.js | 4 ++++ src/managers/SectionDetailManager.js | 15 +++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 78b9b5a65..51d4a741d 100644 --- a/README.md +++ b/README.md @@ -162,7 +162,8 @@ - [x] 사용자가 등록한 노선을 표시해야한다. - [x] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. - - [ ] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. + - [x] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. + - [ ] 새로운 구간 등록시 노선의 상행종점과 하행종점을 업데이트 한다. - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. diff --git a/src/factory/Line.js b/src/factory/Line.js index a4963158d..5b8ba49c0 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -5,4 +5,8 @@ export default class Line { this.endStation = props.endStation; this.section = [this.startStation, this.endStation]; } + + updateSection({ stationName, index }) { + this.section.splice(index, 0, stationName); + } } diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index 79d04ac0b..f77cacfd7 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -25,6 +25,21 @@ export default class SectionDetailManager extends Component { this.table = this.container.querySelector( `#${SECTION_SELECTOR.TABLE_BODY}`, ); + + this.form.addEventListener('submit', this.onSubmit); + } + + onSubmit = (event) => { + event.preventDefault(); + const targetLine = this.data.currentLineData; + targetLine.updateSection(this.getValues()); + this.props.syncData(this.data); + }; + + getValues() { + const { value: stationName } = this.stationSelector; + const { value: index } = this.orderInput; + return { stationName, index }; } updateOptions() { From f4716efe60afabe5f2d526c19310f2bacbbe4152 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 11:27:41 +0900 Subject: [PATCH 27/44] =?UTF-8?q?[feat]=20=EA=B5=AC=EA=B0=84=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=EC=8B=9C=20=EC=83=81=ED=96=89=EC=A2=85=EC=A0=90=20?= =?UTF-8?q?=ED=95=98=ED=96=89=EC=A2=85=EC=A0=90=20=EC=97=85=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- src/factory/Line.js | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 51d4a741d..315223146 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,7 @@ - [x] 사용자가 등록한 노선을 표시해야한다. - [x] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. - [x] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. - - [ ] 새로운 구간 등록시 노선의 상행종점과 하행종점을 업데이트 한다. + - [x] 새로운 구간 등록시 노선의 상행종점과 하행종점을 업데이트 한다. - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. diff --git a/src/factory/Line.js b/src/factory/Line.js index 5b8ba49c0..6171a7d24 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -8,5 +8,15 @@ export default class Line { updateSection({ stationName, index }) { this.section.splice(index, 0, stationName); + this.updateStartStation(); + this.updateEndStation(); + } + + updateStartStation() { + [this.startStation] = this.section; + } + + updateEndStation() { + this.endStation = this.section[this.section.length - 1]; } } From 63d43cf6870bd6404109048e4ce77a88509a7f07 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 11:46:28 +0900 Subject: [PATCH 28/44] =?UTF-8?q?[feat]=20=EC=B4=88=EA=B8=B0=20=EC=9E=91?= =?UTF-8?q?=EB=8F=99=EC=8B=9C=20localStorage=20=EC=98=A4=EB=A5=98=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 초기 진행시 localStorage에 데이터가 없을 경우 작동이 안되던 버그 수정 --- src/managers/LineManager.js | 2 -- src/managers/StationManager.js | 1 - src/share/storage.js | 5 +++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index c8993419e..2efa03ea8 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -13,8 +13,6 @@ export default class LineManager extends Component { constructor(props) { super(props); - this.data.lineList = []; - this.form = this.container.querySelector(`#${LINE_SELECTOR.FORM_ID}`); this.userInput = this.container.querySelector( `#${LINE_SELECTOR.NAME_INPUT_ID}`, diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 672677fc4..b6c4ed588 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -14,7 +14,6 @@ const ALERT_MESSAGE = '노선에 포함되어있어 삭제가 불가능합니다 export default class StationManager extends Component { constructor(props) { super(props); - this.data.stationList = []; this.userInput = this.container.querySelector( `#${STATION_SELECTOR.NAME_INPUT_ID}`, diff --git a/src/share/storage.js b/src/share/storage.js index 15a3c694e..d2d82796b 100644 --- a/src/share/storage.js +++ b/src/share/storage.js @@ -15,9 +15,10 @@ const jsonToClassConverter = (dataList, Creator) => const setItem = (key, data) => localStorage.setItem(key, JSON.stringify(data)); const getItem = (key) => { - const data = JSON.parse(localStorage.getItem(key)); + const tempData = JSON.parse(localStorage.getItem(key)); + const data = tempData || defaultState; data.lineList = jsonToClassConverter(data.lineList, Line); - return data || defaultState; + return data; }; const storage = { From 1572cce199b014e7eb4d70cf0fdc6a9c7d53383a Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 11:55:21 +0900 Subject: [PATCH 29/44] =?UTF-8?q?[feat]=20=EA=B5=AC=EA=B0=84=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D=EC=8B=9C=20=EC=9D=B4=EB=AF=B8=20=EB=85=B8=EC=84=A0?= =?UTF-8?q?=EC=97=90=20=ED=8F=AC=ED=95=A8=EB=90=98=EC=96=B4=EC=9E=88?= =?UTF-8?q?=EB=8A=94=EC=A7=80=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + src/factory/Line.js | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/README.md b/README.md index 315223146..d796bd506 100644 --- a/README.md +++ b/README.md @@ -164,6 +164,7 @@ - [x] 노선을 클릭 시 그 노선을 수정 할 수 있게 해야한다. - [x] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. - [x] 새로운 구간 등록시 노선의 상행종점과 하행종점을 업데이트 한다. + - [x] 구간 등록시 노선에 이미 포함된 역인지 확인한다. - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. diff --git a/src/factory/Line.js b/src/factory/Line.js index 6171a7d24..807900af4 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -1,3 +1,5 @@ +import { checkOverlap } from '../share/utils.js'; + export default class Line { constructor(props) { this.name = props.name; @@ -7,6 +9,10 @@ export default class Line { } updateSection({ stationName, index }) { + if (!checkOverlap(stationName, this.section)) { + alert('이미 노선에 포함되어있습니다'); + return; + } this.section.splice(index, 0, stationName); this.updateStartStation(); this.updateEndStation(); From 476b3f92d7aa9d7f07e56cd4a0e77fdaf112c15e Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 12:35:58 +0900 Subject: [PATCH 30/44] =?UTF-8?q?[feat]=20=EA=B5=AC=EA=B0=84=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=EC=97=90=EC=84=9C=20=EC=97=AD=20=EC=82=AD=EC=A0=9C?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 새로고침시 구간이 제대로 불려오지 않았던 버그 수정 - HTML 오탈자 수정 --- README.md | 4 ++-- index.html | 1 - src/factory/Line.js | 13 +++++++++++-- src/managers/SectionDetailManager.js | 18 ++++++++++++++++-- src/share/selector.js | 2 +- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index d796bd506..d65b541e8 100644 --- a/README.md +++ b/README.md @@ -165,9 +165,9 @@ - [x] 사용자가 입력한 역들을 순서에 따라 추가 할 수 있다. - [x] 새로운 구간 등록시 노선의 상행종점과 하행종점을 업데이트 한다. - [x] 구간 등록시 노선에 이미 포함된 역인지 확인한다. - - [ ] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. + - [x] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. - - [ ] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. + - [x] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. - 노선도 출력 기능 - [ ] 노선의 상행종점부터 하행종점까지 순서대로 목록을 표시해야 한다. diff --git a/index.html b/index.html index 2feab0924..5f7c2a7e9 100644 --- a/index.html +++ b/index.html @@ -102,7 +102,6 @@

구간 등록

-

🚉 지하철 노선 목록

${name}${startStation}${endStation}
${stationName}
${index}${name}
diff --git a/src/factory/Line.js b/src/factory/Line.js index 807900af4..a2d9b8605 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -2,13 +2,16 @@ import { checkOverlap } from '../share/utils.js'; export default class Line { constructor(props) { + this.props = props; this.name = props.name; this.startStation = props.startStation; this.endStation = props.endStation; - this.section = [this.startStation, this.endStation]; + this.section = this.getSection(); } - updateSection({ stationName, index }) { + getSection = () => this.props.section || [this.startStation, this.endStation]; + + addStationToSection({ stationName, index }) { if (!checkOverlap(stationName, this.section)) { alert('이미 노선에 포함되어있습니다'); return; @@ -18,6 +21,12 @@ export default class Line { this.updateEndStation(); } + deleteStationFromSection({ index }) { + this.section.splice(index, 1); + this.updateStartStation(); + this.updateEndStation(); + } + updateStartStation() { [this.startStation] = this.section; } diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index f77cacfd7..b9a7ae072 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -4,6 +4,9 @@ import { optionTemplate, sectionDetailTableTemplate, } from '../share/template.js'; +import { customConfirm } from '../share/utils.js'; + +const CONFIRM_MESSAGE = '정말로 삭제하시겠습니까?'; export default class SectionDetailManager extends Component { constructor(props) { @@ -27,12 +30,23 @@ export default class SectionDetailManager extends Component { ); this.form.addEventListener('submit', this.onSubmit); + this.table.addEventListener('click', this.onTableClick); } onSubmit = (event) => { event.preventDefault(); const targetLine = this.data.currentLineData; - targetLine.updateSection(this.getValues()); + targetLine.addStationToSection(this.getValues()); + this.props.syncData(this.data); + }; + + onTableClick = (event) => { + const { className } = event.target; + const { index } = event.target.dataset; + const targetLine = this.data.currentLineData; + if (className !== SECTION_SELECTOR.DELETE_BUTTON_CLASS) return; + if (!customConfirm(CONFIRM_MESSAGE)) return; + targetLine.deleteStationFromSection({ index }); this.props.syncData(this.data); }; @@ -68,7 +82,7 @@ export default class SectionDetailManager extends Component { sectionDetailTableTemplate({ name: station, index, - buttonClass: SECTION_SELECTOR.DELETE_BUTTON, + buttonClass: SECTION_SELECTOR.DELETE_BUTTON_CLASS, }), ) .join(''); diff --git a/src/share/selector.js b/src/share/selector.js index bfbfecd09..4e7e541c6 100644 --- a/src/share/selector.js +++ b/src/share/selector.js @@ -40,7 +40,7 @@ export const SECTION_SELECTOR = Object.freeze({ STATION_SELECTOR_ID: 'section-station-selector', ORDER_INPUT_ID: 'section-order-input', ADD_BUTTON_ID: 'section-add-button', - DELETE_BUTTON: 'section-delete-button', + DELETE_BUTTON_CLASS: 'section-delete-button', RESULT_CONTAINER_ID: 'section-result', TABLE: 'section-table', TABLE_BODY: 'section-table-body', From f56aca343629703c13ccb3eb2886201cba303bf2 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 12:47:32 +0900 Subject: [PATCH 31/44] =?UTF-8?q?[feat]=20=EA=B5=AC=EA=B0=84=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=EC=8B=9C=20=EB=85=B8=EC=84=A0=EC=9D=98=20=EC=B5=9C?= =?UTF-8?q?=EC=86=8C=20=EA=B8=B8=EC=9D=B4=20=ED=99=95=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 노선은 최소 2개역을 포함해야 하기 때문에 길이가 2인경우 삭제가 불가능 하게 함 --- README.md | 2 +- src/factory/Line.js | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d65b541e8..d59133348 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ - [x] 새로운 구간 등록시 노선의 상행종점과 하행종점을 업데이트 한다. - [x] 구간 등록시 노선에 이미 포함된 역인지 확인한다. - [x] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. - - [ ] 노선에 포함된 역이 두개 이하인지 확인해야한다. + - [x] 노선에 포함된 역이 두개 이하인지 확인해야한다. - [x] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. - 노선도 출력 기능 diff --git a/src/factory/Line.js b/src/factory/Line.js index a2d9b8605..93bcbeae6 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -1,4 +1,8 @@ -import { checkOverlap } from '../share/utils.js'; +import { checkOverlap, checkValueLength } from '../share/utils.js'; + +const MIN_SECTION_LENGTH = 2; +const ALERT_MESSAGE_SECTION_INCLUDES_STATION = '이미 노선에 포함되어있습니다'; +const ALERT_MESSAGE_SECTION_MINLENGTH = '노선은 최소 2개역을 포함해야 합니다.'; export default class Line { constructor(props) { @@ -13,7 +17,7 @@ export default class Line { addStationToSection({ stationName, index }) { if (!checkOverlap(stationName, this.section)) { - alert('이미 노선에 포함되어있습니다'); + alert(ALERT_MESSAGE_SECTION_INCLUDES_STATION); return; } this.section.splice(index, 0, stationName); @@ -22,11 +26,17 @@ export default class Line { } deleteStationFromSection({ index }) { + if (this.checkSectionLength()) { + alert(ALERT_MESSAGE_SECTION_MINLENGTH); + return; + } this.section.splice(index, 1); this.updateStartStation(); this.updateEndStation(); } + checkSectionLength = () => this.section.length === MIN_SECTION_LENGTH; + updateStartStation() { [this.startStation] = this.section; } From 0ac2089026923ad8ff534cfff89f0716e3b5fb49 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 13:09:44 +0900 Subject: [PATCH 32/44] =?UTF-8?q?[feat]=20=EC=98=AC=EB=B0=94=EB=A5=B4?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=9D=80=20=EC=9E=85=EB=A0=A5=EC=9D=BC=20?= =?UTF-8?q?=EA=B2=BD=EC=9A=B0=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 올바르지 않은 입력일 경우 경고창을 표시해 다시 입력할 수 있도록 한다. --- README.md | 7 ++++++- src/factory/Line.js | 2 +- src/managers/LineManager.js | 3 ++- src/managers/StationManager.js | 26 ++++++++++++++++++-------- src/share/utils.js | 2 ++ 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index d59133348..27f433b04 100644 --- a/README.md +++ b/README.md @@ -135,12 +135,13 @@ - [x] state를 공유할 수 있도록 각 메뉴에서 state를 동기화 시킨다. - [x] localStorage를 이용하여 새로고침해도 최근 데이터를 활용해 목록들을 표시한다. - [x] form 제출이 input을 초기화 한다. + - [x] 올바르 않은 입력일 경우 경고창을 표시하여 재입력 할 수 있게한다. - 역 관련 기능 - [x] 사용자가 역 이름을 추가할 수 있게해야 한다. - [x] 역 이름이 중복되는지 확인해야한다. - - [x] 역 이름이 2글자 이상인지 확인해야 한다 + - [x] 역 이름이 2글자 이상인지 확인해야 한다. (미만일 경우 경고창 표시) - [x] 사용자가 입력한 역들을 차례대로 출력해야 한다. - [x] 삭제 버튼을 클릭시 삭제할 수 있게 해야한다. - [x] 삭제에 성공했을 경우 목록을 업데이트해서 다시 표시해야 한다. @@ -170,4 +171,8 @@ - [x] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. - 노선도 출력 기능 + - [ ] 노선의 상행종점부터 하행종점까지 순서대로 목록을 표시해야 한다. + +- 예외사항 + - 입력의 모든 공백은 제외한다. diff --git a/src/factory/Line.js b/src/factory/Line.js index 93bcbeae6..ef0f1fa4a 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -1,4 +1,4 @@ -import { checkOverlap, checkValueLength } from '../share/utils.js'; +import { checkOverlap } from '../share/utils.js'; const MIN_SECTION_LENGTH = 2; const ALERT_MESSAGE_SECTION_INCLUDES_STATION = '이미 노선에 포함되어있습니다'; diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 2efa03ea8..519778336 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -5,6 +5,7 @@ import { checkOverlap, checkSameStation, customConfirm, + deleteWhiteSpace, } from '../share/utils.js'; import { lineTableTemplate, optionTemplate } from '../share/template.js'; @@ -83,7 +84,7 @@ export default class LineManager extends Component { getAllLineNames = () => this.data.lineList.map((line) => line.name); getValues = () => { - const { value: name } = this.userInput; + const name = deleteWhiteSpace(this.userInput.value); const { value: startStation } = this.startStationSelector; const { value: endStation } = this.endStationSelector; return { name, startStation, endStation }; diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index b6c4ed588..0bd32371e 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -4,13 +4,18 @@ import { checkOverlap, checkValueLength, customConfirm, + deleteWhiteSpace, } from '../share/utils.js'; import { stationTableTemplate } from '../share/template.js'; const MIN_STATION_NAME_LENGTH = 2; const CONFIRM_MESSAGE = '정말로 삭제하시겠습니까?'; -const ALERT_MESSAGE = '노선에 포함되어있어 삭제가 불가능합니다.'; +const ALERT_MESSAGE_SECTION_INCLUDES_STATION = + '노선에 포함되어있어 삭제가 불가능합니다.'; +const ALERT_MESSAGE_STATION_MINLENGTH = + '역은 공백을 제외하고 2자 이상이여야 합니다.'; +const ALERT_MESSAGE_ALREADY_INCLUDE = '이미 등록된 역입니다.'; export default class StationManager extends Component { constructor(props) { super(props); @@ -32,8 +37,8 @@ export default class StationManager extends Component { onSubmit = (event) => { event.preventDefault(); - const { value } = this.userInput; - this.addStationToList(value); + const stationName = deleteWhiteSpace(this.userInput.value); + this.addStationToList(stationName); this.clearInput(); }; @@ -44,7 +49,7 @@ export default class StationManager extends Component { if (className !== STATION_SELECTOR.DELETE_BUTTON_CLASS) return; if (!customConfirm(CONFIRM_MESSAGE)) return; if (!checkOverlap(stationName, this.getAllStationNamesInLines())) { - alert(ALERT_MESSAGE); + alert(ALERT_MESSAGE_SECTION_INCLUDES_STATION); return; } this.deleteStationFromList(index); @@ -74,10 +79,15 @@ export default class StationManager extends Component { } checkValidity(value) { - return ( - checkOverlap(value, this.data.stationList) && - checkValueLength(value, MIN_STATION_NAME_LENGTH) - ); + if (!checkOverlap(value, this.data.stationList)) { + alert(ALERT_MESSAGE_ALREADY_INCLUDE); + return false; + } + if (!checkValueLength(value, MIN_STATION_NAME_LENGTH)) { + alert(ALERT_MESSAGE_STATION_MINLENGTH); + return false; + } + return true; } clearInput() { diff --git a/src/share/utils.js b/src/share/utils.js index b64b5a168..8ad56ee52 100644 --- a/src/share/utils.js +++ b/src/share/utils.js @@ -6,3 +6,5 @@ export const checkSameStation = (prevStation, nextStation) => prevStation !== nextStation; export const customConfirm = (message) => confirm(message); + +export const deleteWhiteSpace = (words) => words.replaceAll(' ', ''); From 16e356f1caa23e5216a6461a855f8cc4f4f930f3 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 15:52:35 +0900 Subject: [PATCH 33/44] =?UTF-8?q?[refactor]=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EB=A0=8C=EB=8D=94=ED=95=A8=EC=88=98=20=ED=98=B8?= =?UTF-8?q?=EC=B6=9C=20=EB=B0=A9=EC=A7=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - this.data를 복사해 새로운 값을 동기화 함으로써 렌더링은 값이 변경될때 한번씩만 일어나도록 함 - 노선 등록시 올바르지 않을 경우 경고창 표시 --- src/managers/LineManager.js | 36 +++++++++++++++++++--------------- src/managers/StationManager.js | 18 ++++++++--------- 2 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 519778336..984ca0ddf 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -10,6 +10,8 @@ import { import { lineTableTemplate, optionTemplate } from '../share/template.js'; const CONFIRM_MESSAGE = '정말 노선을 삭제하시겠습니까?'; +const ALERT_MESSAGE_SAME_STATION = '상행 종점과 하행 종점은 달라야 합니다.'; +const ALERT_MESSAGE_SAME_NAME = '이미 등록된 노선이름입니다.'; export default class LineManager extends Component { constructor(props) { super(props); @@ -46,6 +48,7 @@ export default class LineManager extends Component { event.preventDefault(); const constructorObj = this.getValues(); const newLine = new Line(constructorObj); + if (!this.checkValidity(newLine)) return; this.addLineToList(newLine); this.clearInput(); }; @@ -59,27 +62,28 @@ export default class LineManager extends Component { }; addLineToList(line) { - if (!this.checkValidity(line)) return; - const newLineList = [...this.data.lineList]; - newLineList.push(line); - this.setData({ - lineList: newLineList, - }); - this.props.syncData(this.data); + const newData = { ...this.data }; + newData.lineList.push(line); + this.props.syncData(newData); } deleteLineFromList(index) { - const newLineList = [...this.data.lineList]; - newLineList.splice(index, 1); - this.setData({ - lineList: newLineList, - }); - this.props.syncData(this.data); + const newData = { ...this.data }; + newData.lineList.splice(index, 1); + this.props.syncData(newData); } - checkValidity = ({ name, startStation, endStation }) => - checkOverlap(name, this.getAllLineNames()) && - checkSameStation(startStation, endStation); + checkValidity({ name, startStation, endStation }) { + if (!checkOverlap(name, this.data.stationList)) { + alert(ALERT_MESSAGE_SAME_NAME); + return false; + } + if (!checkSameStation(startStation, endStation)) { + alert(ALERT_MESSAGE_SAME_STATION); + return false; + } + return true; + } getAllLineNames = () => this.data.lineList.map((line) => line.name); diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 0bd32371e..3b0bae92c 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -59,19 +59,15 @@ export default class StationManager extends Component { if (!this.checkValidity(station)) return; const newStationList = [...this.data.stationList]; newStationList.push(station); - this.setData({ - stationList: newStationList, - }); - this.props.syncData(this.data); + const newData = { ...this.data }; + newData.stationList.push(station); + this.props.syncData(newData); } deleteStationFromList(index) { - const newStationList = [...this.data.stationList]; - newStationList.splice(index, 1); - this.setData({ - stationList: newStationList, - }); - this.props.syncData(this.data); + const newData = { ...this.data }; + newData.stationList.splice(index, 1); + this.props.syncData(newData); } getAllStationNamesInLines() { @@ -107,6 +103,8 @@ export default class StationManager extends Component { } render() { + console.log('rendered!'); + console.log(this); this.table.innerHTML = this.template(); } } From 6351dfecbfdfee248a2365c978ff5d63ba09591f Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 16:00:22 +0900 Subject: [PATCH 34/44] =?UTF-8?q?[feat]=20=EB=85=B8=EC=84=A0=EC=9D=B4?= =?UTF-8?q?=EB=A6=84=EC=9D=B4=20=EA=B3=B5=EB=B0=B1=EC=9D=B8=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/managers/LineManager.js | 5 +++++ src/managers/StationManager.js | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 984ca0ddf..e43eb99ed 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -12,6 +12,7 @@ import { lineTableTemplate, optionTemplate } from '../share/template.js'; const CONFIRM_MESSAGE = '정말 노선을 삭제하시겠습니까?'; const ALERT_MESSAGE_SAME_STATION = '상행 종점과 하행 종점은 달라야 합니다.'; const ALERT_MESSAGE_SAME_NAME = '이미 등록된 노선이름입니다.'; +const ALERT_MESSAGE_NO_WHITESPACE = '노선이름은 공백으로 지정할 수 없습니다.'; export default class LineManager extends Component { constructor(props) { super(props); @@ -82,6 +83,10 @@ export default class LineManager extends Component { alert(ALERT_MESSAGE_SAME_STATION); return false; } + if (name.length) { + alert(ALERT_MESSAGE_NO_WHITESPACE); + return false; + } return true; } diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 3b0bae92c..74491a678 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -83,6 +83,7 @@ export default class StationManager extends Component { alert(ALERT_MESSAGE_STATION_MINLENGTH); return false; } + return true; } @@ -103,8 +104,6 @@ export default class StationManager extends Component { } render() { - console.log('rendered!'); - console.log(this); this.table.innerHTML = this.template(); } } From 54fc41683c94f59fa6a37cf254044d15d86f342f Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 16:38:56 +0900 Subject: [PATCH 35/44] =?UTF-8?q?[refactor]=20=EC=A4=91=EB=B3=B5=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EB=A9=94=EC=84=9C=EB=93=9C=EB=93=A4=20=EA=B3=B5?= =?UTF-8?q?=EC=9C=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 중복되는 메서드들을 Component Class로 공유하도록 하였다. --- index.html | 2 -- src/factory/Component.js | 20 +++++++++++++ src/managers/LineManager.js | 43 +++++++--------------------- src/managers/SectionDetailManager.js | 20 ++++--------- src/managers/SectionManager.js | 13 +++++++-- src/managers/StationManager.js | 28 ++++-------------- src/share/words.js | 4 +++ 7 files changed, 55 insertions(+), 75 deletions(-) create mode 100644 src/share/words.js diff --git a/index.html b/index.html index 5f7c2a7e9..9eddc5de3 100644 --- a/index.html +++ b/index.html @@ -85,8 +85,6 @@

🚉 지하철 노선 목록

@@ -28,5 +30,14 @@ export const sectionDetailTableTemplate = (data) => { `; }; -export const optionTemplate = (station) => - ``; +export const mapTemplate = (lineList) => lineList + .map((line) => ` +
    +
  • 🚉 ${line.name}

  • +
      + ${line.section.map((stationName) => `
    • ${stationName}
    • `).join('')} +
    +
`) + .join(''); + +export const optionTemplate = (station) => ``; diff --git a/style.css b/style.css new file mode 100644 index 000000000..3debb3c6d --- /dev/null +++ b/style.css @@ -0,0 +1,18 @@ +label { + margin-top: 2rem; + display: block; +} +table, +th, +tr, +td { + border: 1px solid black; +} + +li{ + list-style :none +} + +.dot{ + list-style: disc; +} \ No newline at end of file From b7af1729db35963925f1bd688e4b9c5e203ae7db Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 17:12:35 +0900 Subject: [PATCH 37/44] =?UTF-8?q?[style]=20=EC=82=AC=EC=9A=A9=EB=90=98?= =?UTF-8?q?=EB=8A=94=20=EB=AC=B8=EC=9E=A5=EB=93=A4=20=ED=95=9C=EA=B3=B3?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - alert나 confirm에 사용되는 문장들을 한 곳에서 관리한다 --- src/managers/LineManager.js | 26 ++++++++++---------------- src/managers/SectionDetailManager.js | 17 +++++++---------- src/managers/StationManager.js | 26 +++++++++----------------- src/share/words.js | 21 +++++++++++++++++++++ 4 files changed, 47 insertions(+), 43 deletions(-) diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 1b4da58c5..7281f95f7 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -8,12 +8,8 @@ import { deleteWhiteSpace, } from '../share/utils.js'; import { lineTableTemplate, optionTemplate } from '../share/template.js'; -import { DATA_KEY } from '../share/words.js'; +import { DATA_KEY, LINE_WORDS } from '../share/words.js'; -const CONFIRM_MESSAGE = '정말 노선을 삭제하시겠습니까?'; -const ALERT_MESSAGE_SAME_STATION = '상행 종점과 하행 종점은 달라야 합니다.'; -const ALERT_MESSAGE_SAME_NAME = '이미 등록된 노선이름입니다.'; -const ALERT_MESSAGE_NO_WHITESPACE = '노선이름은 공백으로 지정할 수 없습니다.'; export default class LineManager extends Component { constructor(props) { super(props); @@ -59,21 +55,21 @@ export default class LineManager extends Component { const { className } = event.target; const { index } = event.target.dataset; if (className !== LINE_SELECTOR.DELETE_BUTTON_CLASS) return; - if (!customConfirm(CONFIRM_MESSAGE)) return; + if (!customConfirm(LINE_WORDS.CONFIRM_MESSAGE)) return; this.deleteFromTable(index, DATA_KEY.LINE_LIST); }; checkValidity({ name, startStation, endStation }) { if (!name.length) { - alert(ALERT_MESSAGE_NO_WHITESPACE); + alert(LINE_WORDS.ALERT_MESSAGE_NO_WHITESPACE); return false; } if (!checkOverlap(name, this.getAllLineNames())) { - alert(ALERT_MESSAGE_SAME_NAME); + alert(LINE_WORDS.ALERT_MESSAGE_SAME_NAME); return false; } if (!checkSameStation(startStation, endStation)) { - alert(ALERT_MESSAGE_SAME_STATION); + alert(LINE_WORDS.ALERT_MESSAGE_SAME_STATION); return false; } return true; @@ -90,13 +86,11 @@ export default class LineManager extends Component { template() { return this.data.lineList - .map((line, index) => - lineTableTemplate({ - ...line, - index, - buttonClass: LINE_SELECTOR.DELETE_BUTTON_CLASS, - }), - ) + .map((line, index) => lineTableTemplate({ + ...line, + index, + buttonClass: LINE_SELECTOR.DELETE_BUTTON_CLASS, + })) .join(''); } diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index 58045ff93..6261cc6fc 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -5,8 +5,7 @@ import { sectionDetailTableTemplate, } from '../share/template.js'; import { customConfirm } from '../share/utils.js'; - -const CONFIRM_MESSAGE = '정말로 삭제하시겠습니까?'; +import { SECTION_DETAIL_WORDS } from '../share/words.js'; export default class SectionDetailManager extends Component { constructor(props) { @@ -45,7 +44,7 @@ export default class SectionDetailManager extends Component { const { index } = event.target.dataset; const targetLine = this.data.currentLineData; if (className !== SECTION_SELECTOR.DELETE_BUTTON_CLASS) return; - if (!customConfirm(CONFIRM_MESSAGE)) return; + if (!customConfirm(SECTION_DETAIL_WORDS.CONFIRM_MESSAGE)) return; targetLine.deleteStationFromSection({ index }); this.props.syncData(this.data); }; @@ -69,13 +68,11 @@ export default class SectionDetailManager extends Component { template() { return this.data.currentLineData.section - .map((station, index) => - sectionDetailTableTemplate({ - name: station, - index, - buttonClass: SECTION_SELECTOR.DELETE_BUTTON_CLASS, - }), - ) + .map((station, index) => sectionDetailTableTemplate({ + name: station, + index, + buttonClass: SECTION_SELECTOR.DELETE_BUTTON_CLASS, + })) .join(''); } diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 223249223..fedb9f2cb 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -7,16 +7,10 @@ import { deleteWhiteSpace, } from '../share/utils.js'; import { stationTableTemplate } from '../share/template.js'; -import { DATA_KEY } from '../share/words.js'; +import { DATA_KEY, STATION_WORDS } from '../share/words.js'; const MIN_STATION_NAME_LENGTH = 2; -const CONFIRM_MESSAGE = '정말로 삭제하시겠습니까?'; -const ALERT_MESSAGE_SECTION_INCLUDES_STATION = - '노선에 포함되어있어 삭제가 불가능합니다.'; -const ALERT_MESSAGE_STATION_MINLENGTH = - '역은 공백을 제외하고 2자 이상이여야 합니다.'; -const ALERT_MESSAGE_ALREADY_INCLUDE = '이미 등록된 역입니다.'; export default class StationManager extends Component { constructor(props) { super(props); @@ -49,9 +43,9 @@ export default class StationManager extends Component { const { index } = event.target.dataset; const { name: stationName } = event.target.parentNode.parentNode.dataset; if (className !== STATION_SELECTOR.DELETE_BUTTON_CLASS) return; - if (!customConfirm(CONFIRM_MESSAGE)) return; + if (!customConfirm(STATION_WORDS.CONFIRM_MESSAGE)) return; if (!checkOverlap(stationName, this.getAllStationNamesInLines())) { - alert(ALERT_MESSAGE_SECTION_INCLUDES_STATION); + alert(STATION_WORDS.ALERT_MESSAGE_SECTION_INCLUDES_STATION); return; } this.deleteFromTable(index, DATA_KEY.STATION_LIST); @@ -63,7 +57,7 @@ export default class StationManager extends Component { checkValidity(value) { if (!checkOverlap(value, this.data.stationList)) { - alert(ALERT_MESSAGE_ALREADY_INCLUDE); + alert(STATION_WORDS.ALERT_MESSAGE_ALREADY_INCLUDE); return false; } if (!checkValueLength(value, MIN_STATION_NAME_LENGTH)) { @@ -75,13 +69,11 @@ export default class StationManager extends Component { template() { return this.data.stationList - .map((station, index) => - stationTableTemplate( - station, - index, - STATION_SELECTOR.DELETE_BUTTON_CLASS, - ), - ) + .map((station, index) => stationTableTemplate( + station, + index, + STATION_SELECTOR.DELETE_BUTTON_CLASS, + )) .join(''); } diff --git a/src/share/words.js b/src/share/words.js index fa9c15301..a09c8d656 100644 --- a/src/share/words.js +++ b/src/share/words.js @@ -2,3 +2,24 @@ export const DATA_KEY = { STATION_LIST: 'stationList', LINE_LIST: 'lineList', }; + +export const STATION_WORDS = { + CONFIRM_MESSAGE: '정말로 삭제하시겠습니까?', + ALERT_MESSAGE_SECTION_INCLUDES_STATION: + '노선에 포함되어있어 삭제가 불가능합니다.', + ALERT_MESSAGE_STATION_MINLENGTH: + '역은 공백을 제외하고 2자 이상이여야 합니다.', + ALERT_MESSAGE_ALREADY_INCLUDE: '이미 등록된 역입니다.', + +}; + +export const LINE_WORDS = { + CONFIRM_MESSAGE: '정말 노선을 삭제하시겠습니까?', + ALERT_MESSAGE_SAME_STATION: '상행 종점과 하행 종점은 달라야 합니다.', + ALERT_MESSAGE_SAME_NAME: '이미 등록된 노선이름입니다.', + ALERT_MESSAGE_NO_WHITESPACE: '노선이름은 공백으로 지정할 수 없습니다.', +}; + +export const SECTION_DETAIL_WORDS = { + CONFIRM_MESSAGE: '정말로 삭제하시겠습니까?', +}; From de47d223b1989e57987f20ec3e73ab968f60a5d6 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 17:43:47 +0900 Subject: [PATCH 38/44] =?UTF-8?q?[refactor]=20Line=20Class=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 함수가 하나의 일만 하도록 만들기 위하여 전체적으로 정리함 --- src/factory/Line.js | 10 ---------- src/managers/LineManager.js | 3 +-- src/managers/SectionDetailManager.js | 18 ++++++++++++++++-- src/managers/SectionManager.js | 3 +-- src/managers/StationManager.js | 5 ++--- src/share/utils.js | 5 +---- src/share/words.js | 2 ++ 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/factory/Line.js b/src/factory/Line.js index ef0f1fa4a..a19dda9fb 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -1,8 +1,6 @@ import { checkOverlap } from '../share/utils.js'; const MIN_SECTION_LENGTH = 2; -const ALERT_MESSAGE_SECTION_INCLUDES_STATION = '이미 노선에 포함되어있습니다'; -const ALERT_MESSAGE_SECTION_MINLENGTH = '노선은 최소 2개역을 포함해야 합니다.'; export default class Line { constructor(props) { @@ -16,20 +14,12 @@ export default class Line { getSection = () => this.props.section || [this.startStation, this.endStation]; addStationToSection({ stationName, index }) { - if (!checkOverlap(stationName, this.section)) { - alert(ALERT_MESSAGE_SECTION_INCLUDES_STATION); - return; - } this.section.splice(index, 0, stationName); this.updateStartStation(); this.updateEndStation(); } deleteStationFromSection({ index }) { - if (this.checkSectionLength()) { - alert(ALERT_MESSAGE_SECTION_MINLENGTH); - return; - } this.section.splice(index, 1); this.updateStartStation(); this.updateEndStation(); diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 7281f95f7..3328f365f 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -4,7 +4,6 @@ import { LINE_SELECTOR } from '../share/selector.js'; import { checkOverlap, checkSameStation, - customConfirm, deleteWhiteSpace, } from '../share/utils.js'; import { lineTableTemplate, optionTemplate } from '../share/template.js'; @@ -55,7 +54,7 @@ export default class LineManager extends Component { const { className } = event.target; const { index } = event.target.dataset; if (className !== LINE_SELECTOR.DELETE_BUTTON_CLASS) return; - if (!customConfirm(LINE_WORDS.CONFIRM_MESSAGE)) return; + if (!confirm(LINE_WORDS.CONFIRM_MESSAGE)) return; this.deleteFromTable(index, DATA_KEY.LINE_LIST); }; diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index 6261cc6fc..9c8f3ba30 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -4,7 +4,7 @@ import { optionTemplate, sectionDetailTableTemplate, } from '../share/template.js'; -import { customConfirm } from '../share/utils.js'; +import { checkOverlap } from '../share/utils.js'; import { SECTION_DETAIL_WORDS } from '../share/words.js'; export default class SectionDetailManager extends Component { @@ -35,6 +35,7 @@ export default class SectionDetailManager extends Component { onSubmit = (event) => { event.preventDefault(); const targetLine = this.data.currentLineData; + if (!this.checkValidity(targetLine)) return; targetLine.addStationToSection(this.getValues()); this.props.syncData(this.data); }; @@ -44,11 +45,24 @@ export default class SectionDetailManager extends Component { const { index } = event.target.dataset; const targetLine = this.data.currentLineData; if (className !== SECTION_SELECTOR.DELETE_BUTTON_CLASS) return; - if (!customConfirm(SECTION_DETAIL_WORDS.CONFIRM_MESSAGE)) return; + if (!confirm(SECTION_DETAIL_WORDS.CONFIRM_MESSAGE)) return; + if (targetLine.checkSectionLength()) { + alert(SECTION_DETAIL_WORDS.ALERT_MESSAGE_SECTION_MINLENGTH); + return; + } targetLine.deleteStationFromSection({ index }); this.props.syncData(this.data); }; + checkValidity(targetLine) { + const { stationName } = this.getValues(); + if (!checkOverlap(stationName, targetLine.section)) { + alert(SECTION_DETAIL_WORDS.ALERT_MESSAGE_SECTION_INCLUDES_STATION); + return false; + } + return true; + } + getValues() { const { value: stationName } = this.stationSelector; const { value: index } = this.userInput; diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index 7ad25b7cd..5fe33fbc8 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -31,8 +31,7 @@ export default class SectionManager extends Component { this.sectionDetailManager.show(); }; - getSelectedLine = (name) => - this.data.lineList.find((line) => line.name === name); + getSelectedLine = (name) => this.data.lineList.find((line) => line.name === name); updateMenuList() { this.sectionLineMenu.innerHTML = this.data.lineList diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index fedb9f2cb..2a01025e3 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -3,7 +3,6 @@ import { STATION_SELECTOR } from '../share/selector.js'; import { checkOverlap, checkValueLength, - customConfirm, deleteWhiteSpace, } from '../share/utils.js'; import { stationTableTemplate } from '../share/template.js'; @@ -43,7 +42,7 @@ export default class StationManager extends Component { const { index } = event.target.dataset; const { name: stationName } = event.target.parentNode.parentNode.dataset; if (className !== STATION_SELECTOR.DELETE_BUTTON_CLASS) return; - if (!customConfirm(STATION_WORDS.CONFIRM_MESSAGE)) return; + if (!confirm(STATION_WORDS.CONFIRM_MESSAGE)) return; if (!checkOverlap(stationName, this.getAllStationNamesInLines())) { alert(STATION_WORDS.ALERT_MESSAGE_SECTION_INCLUDES_STATION); return; @@ -61,7 +60,7 @@ export default class StationManager extends Component { return false; } if (!checkValueLength(value, MIN_STATION_NAME_LENGTH)) { - alert(ALERT_MESSAGE_STATION_MINLENGTH); + alert(STATION_WORDS.ALERT_MESSAGE_STATION_MINLENGTH); return false; } return true; diff --git a/src/share/utils.js b/src/share/utils.js index 8ad56ee52..4771b9830 100644 --- a/src/share/utils.js +++ b/src/share/utils.js @@ -2,9 +2,6 @@ export const checkOverlap = (value, list) => !list.includes(value); export const checkValueLength = (value, minLength) => value.length >= minLength; -export const checkSameStation = (prevStation, nextStation) => - prevStation !== nextStation; - -export const customConfirm = (message) => confirm(message); +export const checkSameStation = (prevStation, nextStation) => prevStation !== nextStation; export const deleteWhiteSpace = (words) => words.replaceAll(' ', ''); diff --git a/src/share/words.js b/src/share/words.js index a09c8d656..5110238e4 100644 --- a/src/share/words.js +++ b/src/share/words.js @@ -22,4 +22,6 @@ export const LINE_WORDS = { export const SECTION_DETAIL_WORDS = { CONFIRM_MESSAGE: '정말로 삭제하시겠습니까?', + ALERT_MESSAGE_SECTION_INCLUDES_STATION: '이미 노선에 포함되어있습니다', + ALERT_MESSAGE_SECTION_MINLENGTH: '노선은 최소 2개역을 포함해야 합니다.', }; From 530958b1f3ad532b5cc103bcb457fc888e548ac8 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 17:59:22 +0900 Subject: [PATCH 39/44] =?UTF-8?q?[refactor]=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EC=9D=98=20=EC=88=9C=EC=84=9C=20=ED=86=B5=EC=9D=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 메서드의 순서를 통일해 각 Manager의 역할을 알기 쉽게 함 --- src/factory/Component.js | 4 +- src/factory/Line.js | 2 - src/index.js | 74 ++-------------------------------- src/managers/LineManager.js | 18 ++++----- src/managers/StationManager.js | 8 ++-- src/managers/app.js | 72 +++++++++++++++++++++++++++++++++ src/share/storage.js | 3 +- 7 files changed, 90 insertions(+), 91 deletions(-) create mode 100644 src/managers/app.js diff --git a/src/factory/Component.js b/src/factory/Component.js index 4e48a20ce..31d3bb021 100644 --- a/src/factory/Component.js +++ b/src/factory/Component.js @@ -11,7 +11,7 @@ export default class Component { ...this.data, ...nextData, }; - this.render(); + this.render?.(); } clearInput() { @@ -41,6 +41,4 @@ export default class Component { hide() { this.container.style.display = 'none'; } - - render() {} } diff --git a/src/factory/Line.js b/src/factory/Line.js index a19dda9fb..060b02d42 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -1,5 +1,3 @@ -import { checkOverlap } from '../share/utils.js'; - const MIN_SECTION_LENGTH = 2; export default class Line { diff --git a/src/index.js b/src/index.js index 1639c880b..15a4760fc 100644 --- a/src/index.js +++ b/src/index.js @@ -1,73 +1,5 @@ -import Component from './factory/Component.js'; -import LineManager from './managers/LineManager.js'; -import MapPrintManager from './managers/MapPrintManager.js'; -import SectionManager from './managers/SectionManager.js'; -import StationManager from './managers/StationManager.js'; -import { - MENU, - STATION_SELECTOR, - LINE_SELECTOR, - SECTION_SELECTOR, - MAP_SELECTOR, -} from './share/selector.js'; -import storage from './share/storage.js'; +import SubwayManager from './managers/app.js'; -const STORAGE_KEY = 'data'; -export default class SubwayManager extends Component { - constructor() { - super(); - this.data = storage.getItem(STORAGE_KEY); - this.menu = document.querySelector(`#${MENU.MENU_CONTAINER_ID}`); +const app = new SubwayManager(); - this.stationManager = new StationManager({ - managerId: MENU.STATION_MANGER_BUTTON_ID, - containerId: STATION_SELECTOR.MANAGER_CONTAINER_ID, - syncData: this.syncData, - }); - this.lineManager = new LineManager({ - managerId: MENU.LINE_MANAGER_BUTTON_ID, - containerId: LINE_SELECTOR.MANAGER_CONTAINER_ID, - syncData: this.syncData, - }); - this.sectionManager = new SectionManager({ - managerId: MENU.SECTION_MANAGER_BUTTON_ID, - containerId: SECTION_SELECTOR.MANAGER_CONTAINER_ID, - syncData: this.syncData, - }); - this.mapPrintManager = new MapPrintManager({ - managerId: MENU.MAP_PRINT_MANAGER_BUTTON_ID, - containerId: MAP_SELECTOR.PRINT_MANAGER_CONTAINER_ID, - syncData: this.syncData, - }); - - this.menu.addEventListener('click', this.changeMenu); - - this.syncData(this.data); - } - - changeMenu = (event) => { - const { nodeName } = event.target; - const { id } = event.target; - if (nodeName !== 'BUTTON') return; - [ - this.stationManager, - this.lineManager, - this.sectionManager, - this.mapPrintManager, - ].forEach((manager) => { - manager.managerId === id ? manager.show() : manager.hide(); - }); - }; - - syncData = (data) => { - storage.setItem(STORAGE_KEY, data); - this.setData(data); - this.stationManager.setData(data); - this.lineManager.setData(data); - this.sectionManager.setData(data); - this.sectionManager.sectionDetailManager.setData(data); - this.mapPrintManager.setData(data); - }; -} - -new SubwayManager(); +app.init(); diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 3328f365f..3ab79e222 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -32,15 +32,6 @@ export default class LineManager extends Component { this.table.addEventListener('click', this.onTableClick); } - updateStationList() { - this.startStationSelector.innerHTML = this.data.stationList - .map((station) => optionTemplate(station)) - .join(''); - this.endStationSelector.innerHTML = this.data.stationList - .map((station) => optionTemplate(station)) - .join(''); - } - onSubmit = (event) => { event.preventDefault(); const constructorObj = this.getValues(); @@ -83,6 +74,15 @@ export default class LineManager extends Component { return { name, startStation, endStation }; }; + updateStationList() { + this.startStationSelector.innerHTML = this.data.stationList + .map((station) => optionTemplate(station)) + .join(''); + this.endStationSelector.innerHTML = this.data.stationList + .map((station) => optionTemplate(station)) + .join(''); + } + template() { return this.data.lineList .map((line, index) => lineTableTemplate({ diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 2a01025e3..c89d5d6da 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -50,10 +50,6 @@ export default class StationManager extends Component { this.deleteFromTable(index, DATA_KEY.STATION_LIST); }; - getAllStationNamesInLines() { - return [...new Set(this.data.lineList.map((line) => line.section).flat())]; - } - checkValidity(value) { if (!checkOverlap(value, this.data.stationList)) { alert(STATION_WORDS.ALERT_MESSAGE_ALREADY_INCLUDE); @@ -66,6 +62,10 @@ export default class StationManager extends Component { return true; } + getAllStationNamesInLines() { + return [...new Set(this.data.lineList.map((line) => line.section).flat())]; + } + template() { return this.data.stationList .map((station, index) => stationTableTemplate( diff --git a/src/managers/app.js b/src/managers/app.js new file mode 100644 index 000000000..3b62e7225 --- /dev/null +++ b/src/managers/app.js @@ -0,0 +1,72 @@ +import Component from '../factory/Component.js'; +import LineManager from './LineManager.js'; +import MapPrintManager from './MapPrintManager.js'; +import SectionManager from './SectionManager.js'; +import StationManager from './StationManager.js'; +import { + MENU, + STATION_SELECTOR, + LINE_SELECTOR, + SECTION_SELECTOR, + MAP_SELECTOR, +} from '../share/selector.js'; +import storage from '../share/storage.js'; + +const STORAGE_KEY = 'data'; +export default class SubwayManager extends Component { + constructor() { + super(); + this.data = storage.getItem(STORAGE_KEY); + this.menu = document.querySelector(`#${MENU.MENU_CONTAINER_ID}`); + + this.stationManager = new StationManager({ + managerId: MENU.STATION_MANGER_BUTTON_ID, + containerId: STATION_SELECTOR.MANAGER_CONTAINER_ID, + syncData: this.syncData, + }); + this.lineManager = new LineManager({ + managerId: MENU.LINE_MANAGER_BUTTON_ID, + containerId: LINE_SELECTOR.MANAGER_CONTAINER_ID, + syncData: this.syncData, + }); + this.sectionManager = new SectionManager({ + managerId: MENU.SECTION_MANAGER_BUTTON_ID, + containerId: SECTION_SELECTOR.MANAGER_CONTAINER_ID, + syncData: this.syncData, + }); + this.mapPrintManager = new MapPrintManager({ + managerId: MENU.MAP_PRINT_MANAGER_BUTTON_ID, + containerId: MAP_SELECTOR.PRINT_MANAGER_CONTAINER_ID, + syncData: this.syncData, + }); + } + + init() { + this.syncData(this.data); + this.menu.addEventListener('click', this.changeMenu); + } + + changeMenu = (event) => { + const { nodeName } = event.target; + const { id } = event.target; + if (nodeName !== 'BUTTON') return; + [ + this.stationManager, + this.lineManager, + this.sectionManager, + this.mapPrintManager, + ].forEach((manager) => { + manager.managerId === id ? manager.show() : manager.hide(); + }); + }; + + syncData = (data) => { + storage.setItem(STORAGE_KEY, data); + this.setData(data); + this.stationManager.setData(data); + this.lineManager.setData(data); + this.sectionManager.setData(data); + this.sectionManager.sectionDetailManager.setData(data); + this.mapPrintManager.setData(data); + }; +} diff --git a/src/share/storage.js b/src/share/storage.js index d2d82796b..ab3c74b39 100644 --- a/src/share/storage.js +++ b/src/share/storage.js @@ -9,8 +9,7 @@ const defaultState = { }, }; -const jsonToClassConverter = (dataList, Creator) => - dataList.map((data) => new Creator(data)); +const jsonToClassConverter = (dataList, Creator) => dataList.map((data) => new Creator(data)); const setItem = (key, data) => localStorage.setItem(key, JSON.stringify(data)); From decf895440a9cf806b9e54a992daa4d4674b9070 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 18:29:52 +0900 Subject: [PATCH 40/44] =?UTF-8?q?[refactor]=20=EB=8D=B0=EC=9D=B4=ED=84=B0?= =?UTF-8?q?=20=EB=8F=99=EA=B8=B0=ED=99=94=20=EB=B0=A9=EB=B2=95=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Component Class에서 syncData 메서드를 등록해 사용할 수 있도록 함 - import 의 순서를 중요도 순으로 변경함 - template 에서 arguments를 전부 객체 형식으로 전달함 --- src/factory/Component.js | 5 +++-- src/managers/SectionDetailManager.js | 4 ++-- src/managers/SectionManager.js | 18 +++++++++--------- src/managers/StationManager.js | 8 +++++--- src/managers/app.js | 7 +++---- src/share/storage.js | 2 ++ src/share/template.js | 16 +++++----------- 7 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/factory/Component.js b/src/factory/Component.js index 31d3bb021..b7e84eb9e 100644 --- a/src/factory/Component.js +++ b/src/factory/Component.js @@ -3,6 +3,7 @@ export default class Component { this.data = {}; this.props = props; this.managerId = props.managerId; + this.syncData = props.syncData; this.container = document.querySelector(`#${props.containerId}`); } @@ -21,13 +22,13 @@ export default class Component { addToTable(value, keyName) { const newData = { ...this.data }; newData[keyName].push(value); - this.props.syncData(newData); + this.syncData(newData); } deleteFromTable(index, keyName) { const newData = { ...this.data }; newData[keyName].splice(index, 1); - this.props.syncData(newData); + this.syncData(newData); } updateTable(template) { diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index 9c8f3ba30..86c84b5fe 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -37,7 +37,7 @@ export default class SectionDetailManager extends Component { const targetLine = this.data.currentLineData; if (!this.checkValidity(targetLine)) return; targetLine.addStationToSection(this.getValues()); - this.props.syncData(this.data); + this.syncData(this.data); }; onTableClick = (event) => { @@ -51,7 +51,7 @@ export default class SectionDetailManager extends Component { return; } targetLine.deleteStationFromSection({ index }); - this.props.syncData(this.data); + this.syncData(this.data); }; checkValidity(targetLine) { diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index 5fe33fbc8..595589c25 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -1,6 +1,6 @@ import Component from '../factory/Component.js'; -import { SECTION_SELECTOR } from '../share/selector.js'; import SectionDetailManager from './SectionDetailManager.js'; +import { SECTION_SELECTOR } from '../share/selector.js'; export default class SectionManager extends Component { constructor(props) { @@ -11,13 +11,10 @@ export default class SectionManager extends Component { ); this.sectionDetailManager = new SectionDetailManager({ containerId: SECTION_SELECTOR.DETAIL_CONTAINER_ID, - syncData: this.props.syncData, + syncData: this.syncData, }); - this.sectionLineMenu.addEventListener( - 'click', - this.changeSectionDetailManger, - ); + this.sectionLineMenu.addEventListener('click', this.changeSectionDetailManger); this.sectionDetailManager.hide(); } @@ -25,9 +22,12 @@ export default class SectionManager extends Component { changeSectionDetailManger = (event) => { if (event.target.nodeName !== 'BUTTON') return; const { name: selectedLineName } = event.target.dataset; - this.sectionDetailManager.setData({ - currentLineData: this.getSelectedLine(selectedLineName), - }); + const newData = { + ...this.data, + currentLineData: + this.getSelectedLine(selectedLineName), + }; + this.syncData(newData); this.sectionDetailManager.show(); }; diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index c89d5d6da..693c92fdf 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -69,9 +69,11 @@ export default class StationManager extends Component { template() { return this.data.stationList .map((station, index) => stationTableTemplate( - station, - index, - STATION_SELECTOR.DELETE_BUTTON_CLASS, + { + stationName: station, + index, + buttonClass: STATION_SELECTOR.DELETE_BUTTON_CLASS, + }, )) .join(''); } diff --git a/src/managers/app.js b/src/managers/app.js index 3b62e7225..2420dfacd 100644 --- a/src/managers/app.js +++ b/src/managers/app.js @@ -1,8 +1,8 @@ import Component from '../factory/Component.js'; +import StationManager from './StationManager.js'; import LineManager from './LineManager.js'; -import MapPrintManager from './MapPrintManager.js'; import SectionManager from './SectionManager.js'; -import StationManager from './StationManager.js'; +import MapPrintManager from './MapPrintManager.js'; import { MENU, STATION_SELECTOR, @@ -10,9 +10,8 @@ import { SECTION_SELECTOR, MAP_SELECTOR, } from '../share/selector.js'; -import storage from '../share/storage.js'; +import storage, { STORAGE_KEY } from '../share/storage.js'; -const STORAGE_KEY = 'data'; export default class SubwayManager extends Component { constructor() { super(); diff --git a/src/share/storage.js b/src/share/storage.js index ab3c74b39..d6b874d45 100644 --- a/src/share/storage.js +++ b/src/share/storage.js @@ -1,5 +1,7 @@ import Line from '../factory/Line.js'; +export const STORAGE_KEY = 'data'; + const defaultState = { stationList: [], lineList: [], diff --git a/src/share/template.js b/src/share/template.js index 3b0b90e9c..00208cad6 100644 --- a/src/share/template.js +++ b/src/share/template.js @@ -1,15 +1,13 @@ -export const stationTableTemplate = (stationName, index, buttonClass) => ` +export const stationTableTemplate = ({ stationName, index, buttonClass }) => ` `; -export const lineTableTemplate = (data) => { - const { - name, startStation, endStation, index, buttonClass, - } = data; - return ` +export const lineTableTemplate = ({ + name, startStation, endStation, index, buttonClass, +}) => ` @@ -17,18 +15,14 @@ export const lineTableTemplate = (data) => { `; -}; -export const sectionDetailTableTemplate = (data) => { - const { index, name, buttonClass } = data; - return ` +export const sectionDetailTableTemplate = ({ index, name, buttonClass }) => ` `; -}; export const mapTemplate = (lineList) => lineList .map((line) => ` From 3ddc5b0e3bcd3de0ba4e12f9a85098ec8ade0cd3 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 19:20:01 +0900 Subject: [PATCH 41/44] =?UTF-8?q?[refactor]=20=EA=B3=B5=EB=B0=B1=EC=9E=85?= =?UTF-8?q?=EB=A0=A5=20=EC=B2=B4=ED=81=AC=20=EB=B0=A9=EC=8B=9D=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++- src/managers/LineManager.js | 3 ++- src/managers/SectionDetailManager.js | 8 ++++++-- src/share/utils.js | 2 ++ src/share/words.js | 1 + 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 27f433b04..b0930615f 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,8 @@ - 노선도 출력 기능 - - [ ] 노선의 상행종점부터 하행종점까지 순서대로 목록을 표시해야 한다. + - [x] 노선의 상행종점부터 하행종점까지 순서대로 목록을 표시해야 한다. - 예외사항 - 입력의 모든 공백은 제외한다. + diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 3ab79e222..107e57f39 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -5,6 +5,7 @@ import { checkOverlap, checkSameStation, deleteWhiteSpace, + isEmpty, } from '../share/utils.js'; import { lineTableTemplate, optionTemplate } from '../share/template.js'; import { DATA_KEY, LINE_WORDS } from '../share/words.js'; @@ -50,7 +51,7 @@ export default class LineManager extends Component { }; checkValidity({ name, startStation, endStation }) { - if (!name.length) { + if (isEmpty(name)) { alert(LINE_WORDS.ALERT_MESSAGE_NO_WHITESPACE); return false; } diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index 86c84b5fe..683a8e691 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -4,7 +4,7 @@ import { optionTemplate, sectionDetailTableTemplate, } from '../share/template.js'; -import { checkOverlap } from '../share/utils.js'; +import { checkOverlap, isEmpty } from '../share/utils.js'; import { SECTION_DETAIL_WORDS } from '../share/words.js'; export default class SectionDetailManager extends Component { @@ -55,11 +55,15 @@ export default class SectionDetailManager extends Component { }; checkValidity(targetLine) { - const { stationName } = this.getValues(); + const { stationName, index } = this.getValues(); if (!checkOverlap(stationName, targetLine.section)) { alert(SECTION_DETAIL_WORDS.ALERT_MESSAGE_SECTION_INCLUDES_STATION); return false; } + if (isEmpty(index)) { + alert(SECTION_DETAIL_WORDS.ALERT_MESSAGE_NO_INDEX); + return false; + } return true; } diff --git a/src/share/utils.js b/src/share/utils.js index 4771b9830..b812f37b2 100644 --- a/src/share/utils.js +++ b/src/share/utils.js @@ -5,3 +5,5 @@ export const checkValueLength = (value, minLength) => value.length >= minLength; export const checkSameStation = (prevStation, nextStation) => prevStation !== nextStation; export const deleteWhiteSpace = (words) => words.replaceAll(' ', ''); + +export const isEmpty = (value) => value === ''; diff --git a/src/share/words.js b/src/share/words.js index 5110238e4..c76f22668 100644 --- a/src/share/words.js +++ b/src/share/words.js @@ -24,4 +24,5 @@ export const SECTION_DETAIL_WORDS = { CONFIRM_MESSAGE: '정말로 삭제하시겠습니까?', ALERT_MESSAGE_SECTION_INCLUDES_STATION: '이미 노선에 포함되어있습니다', ALERT_MESSAGE_SECTION_MINLENGTH: '노선은 최소 2개역을 포함해야 합니다.', + ALERT_MESSAGE_NO_INDEX: '순서를 입력해주세요', }; From eb7c22c5ba681c5ea2ec03b7c98c9f01c978842d Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 19:42:00 +0900 Subject: [PATCH 42/44] =?UTF-8?q?[refactor]=20=ED=95=A8=EC=88=98=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD=20&=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EC=9A=94=EC=86=8C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 유효성을 검사하는 함수들의 이름을 직관적으로 이해하기 쉽게 변경함 ex) check => isValid - add버튼에 직접적으로 이벤트를 거는것이 아니고 form 이벤트를 이용하기 때문에 불필요한 돔에 접근을 최소하함 --- src/managers/LineManager.js | 15 ++++++--------- src/managers/SectionDetailManager.js | 11 ++++------- src/managers/StationManager.js | 17 +++++++---------- src/share/utils.js | 10 +++++----- 4 files changed, 22 insertions(+), 31 deletions(-) diff --git a/src/managers/LineManager.js b/src/managers/LineManager.js index 107e57f39..44e49518d 100644 --- a/src/managers/LineManager.js +++ b/src/managers/LineManager.js @@ -2,8 +2,8 @@ import Component from '../factory/Component.js'; import Line from '../factory/Line.js'; import { LINE_SELECTOR } from '../share/selector.js'; import { - checkOverlap, - checkSameStation, + isOverlap, + isSameStation, deleteWhiteSpace, isEmpty, } from '../share/utils.js'; @@ -24,9 +24,6 @@ export default class LineManager extends Component { this.endStationSelector = this.container.querySelector( `#${LINE_SELECTOR.END_STATION_SELECTOR}`, ); - this.addButton = this.container.querySelector( - `#${LINE_SELECTOR.ADD_BUTTON_ID}`, - ); this.table = this.container.querySelector(`#${LINE_SELECTOR.TABLE_BODY}`); this.form.addEventListener('submit', this.onSubmit); @@ -37,7 +34,7 @@ export default class LineManager extends Component { event.preventDefault(); const constructorObj = this.getValues(); const newLine = new Line(constructorObj); - if (!this.checkValidity(newLine)) return; + if (!this.isValid(newLine)) return; this.addToTable(newLine, DATA_KEY.LINE_LIST); this.clearInput(); }; @@ -50,16 +47,16 @@ export default class LineManager extends Component { this.deleteFromTable(index, DATA_KEY.LINE_LIST); }; - checkValidity({ name, startStation, endStation }) { + isValid({ name, startStation, endStation }) { if (isEmpty(name)) { alert(LINE_WORDS.ALERT_MESSAGE_NO_WHITESPACE); return false; } - if (!checkOverlap(name, this.getAllLineNames())) { + if (isOverlap(name, this.getAllLineNames())) { alert(LINE_WORDS.ALERT_MESSAGE_SAME_NAME); return false; } - if (!checkSameStation(startStation, endStation)) { + if (isSameStation(startStation, endStation)) { alert(LINE_WORDS.ALERT_MESSAGE_SAME_STATION); return false; } diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index 683a8e691..077edfe9d 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -4,7 +4,7 @@ import { optionTemplate, sectionDetailTableTemplate, } from '../share/template.js'; -import { checkOverlap, isEmpty } from '../share/utils.js'; +import { isOverlap, isEmpty } from '../share/utils.js'; import { SECTION_DETAIL_WORDS } from '../share/words.js'; export default class SectionDetailManager extends Component { @@ -21,9 +21,6 @@ export default class SectionDetailManager extends Component { this.userInput = this.container.querySelector( `#${SECTION_SELECTOR.ORDER_INPUT_ID}`, ); - this.addButton = this.container.querySelector( - `#${SECTION_SELECTOR.ADD_BUTTON_ID}`, - ); this.table = this.container.querySelector( `#${SECTION_SELECTOR.TABLE_BODY}`, ); @@ -35,7 +32,7 @@ export default class SectionDetailManager extends Component { onSubmit = (event) => { event.preventDefault(); const targetLine = this.data.currentLineData; - if (!this.checkValidity(targetLine)) return; + if (!this.isValid(targetLine)) return; targetLine.addStationToSection(this.getValues()); this.syncData(this.data); }; @@ -54,9 +51,9 @@ export default class SectionDetailManager extends Component { this.syncData(this.data); }; - checkValidity(targetLine) { + isValid(targetLine) { const { stationName, index } = this.getValues(); - if (!checkOverlap(stationName, targetLine.section)) { + if (isOverlap(stationName, targetLine.section)) { alert(SECTION_DETAIL_WORDS.ALERT_MESSAGE_SECTION_INCLUDES_STATION); return false; } diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index 693c92fdf..f468f7b3f 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -1,8 +1,8 @@ import Component from '../factory/Component.js'; import { STATION_SELECTOR } from '../share/selector.js'; import { - checkOverlap, - checkValueLength, + isOverlap, + isValidLength, deleteWhiteSpace, } from '../share/utils.js'; import { stationTableTemplate } from '../share/template.js'; @@ -17,9 +17,6 @@ export default class StationManager extends Component { this.userInput = this.container.querySelector( `#${STATION_SELECTOR.NAME_INPUT_ID}`, ); - this.addButton = this.container.querySelector( - `#${STATION_SELECTOR.ADD_BUTTON_ID}`, - ); this.form = this.container.querySelector(`#${STATION_SELECTOR.FORM_ID}`); this.table = this.container.querySelector( `#${STATION_SELECTOR.TABLE_BODY}`, @@ -32,7 +29,7 @@ export default class StationManager extends Component { onSubmit = (event) => { event.preventDefault(); const stationName = deleteWhiteSpace(this.userInput.value); - if (!this.checkValidity(stationName)) return; + if (!this.isValid(stationName)) return; this.addToTable(stationName, DATA_KEY.STATION_LIST); this.clearInput(); }; @@ -43,19 +40,19 @@ export default class StationManager extends Component { const { name: stationName } = event.target.parentNode.parentNode.dataset; if (className !== STATION_SELECTOR.DELETE_BUTTON_CLASS) return; if (!confirm(STATION_WORDS.CONFIRM_MESSAGE)) return; - if (!checkOverlap(stationName, this.getAllStationNamesInLines())) { + if (isOverlap(stationName, this.getAllStationNamesInLines())) { alert(STATION_WORDS.ALERT_MESSAGE_SECTION_INCLUDES_STATION); return; } this.deleteFromTable(index, DATA_KEY.STATION_LIST); }; - checkValidity(value) { - if (!checkOverlap(value, this.data.stationList)) { + isValid(value) { + if (isOverlap(value, this.data.stationList)) { alert(STATION_WORDS.ALERT_MESSAGE_ALREADY_INCLUDE); return false; } - if (!checkValueLength(value, MIN_STATION_NAME_LENGTH)) { + if (!isValidLength(value, MIN_STATION_NAME_LENGTH)) { alert(STATION_WORDS.ALERT_MESSAGE_STATION_MINLENGTH); return false; } diff --git a/src/share/utils.js b/src/share/utils.js index b812f37b2..b3d8bf6f6 100644 --- a/src/share/utils.js +++ b/src/share/utils.js @@ -1,9 +1,9 @@ -export const checkOverlap = (value, list) => !list.includes(value); +export const isOverlap = (value, list) => list.includes(value); -export const checkValueLength = (value, minLength) => value.length >= minLength; +export const isValidLength = (value, minLength) => value.length >= minLength; -export const checkSameStation = (prevStation, nextStation) => prevStation !== nextStation; - -export const deleteWhiteSpace = (words) => words.replaceAll(' ', ''); +export const isSameStation = (prevStation, nextStation) => prevStation === nextStation; export const isEmpty = (value) => value === ''; + +export const deleteWhiteSpace = (words) => words.replaceAll(' ', ''); From a7d591af01db2d5c6656d5d8b21b6de650eef409 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 20:30:39 +0900 Subject: [PATCH 43/44] =?UTF-8?q?[refactor]=20=ED=95=A8=EC=88=98=EB=AA=85?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 의미를 명확하게 하기 위하여 getSection => setSection 으로 이름변경 - 함수의 활용성을 높이기 위해 isEmpty함수가 문자열 배열 모두 검사할수 있 도록 변경 --- src/factory/Line.js | 4 ++-- src/managers/SectionDetailManager.js | 9 +++++---- src/managers/SectionManager.js | 3 ++- src/managers/StationManager.js | 12 +++++------- src/managers/app.js | 11 ++++++++--- src/share/utils.js | 2 +- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/factory/Line.js b/src/factory/Line.js index 060b02d42..e151d227b 100644 --- a/src/factory/Line.js +++ b/src/factory/Line.js @@ -6,10 +6,10 @@ export default class Line { this.name = props.name; this.startStation = props.startStation; this.endStation = props.endStation; - this.section = this.getSection(); + this.section = this.setSection(); } - getSection = () => this.props.section || [this.startStation, this.endStation]; + setSection = () => this.props.section || [this.startStation, this.endStation]; addStationToSection({ stationName, index }) { this.section.splice(index, 0, stationName); diff --git a/src/managers/SectionDetailManager.js b/src/managers/SectionDetailManager.js index 077edfe9d..ff9a1c5bc 100644 --- a/src/managers/SectionDetailManager.js +++ b/src/managers/SectionDetailManager.js @@ -34,6 +34,7 @@ export default class SectionDetailManager extends Component { const targetLine = this.data.currentLineData; if (!this.isValid(targetLine)) return; targetLine.addStationToSection(this.getValues()); + this.clearInput(); this.syncData(this.data); }; @@ -53,14 +54,14 @@ export default class SectionDetailManager extends Component { isValid(targetLine) { const { stationName, index } = this.getValues(); - if (isOverlap(stationName, targetLine.section)) { - alert(SECTION_DETAIL_WORDS.ALERT_MESSAGE_SECTION_INCLUDES_STATION); - return false; - } if (isEmpty(index)) { alert(SECTION_DETAIL_WORDS.ALERT_MESSAGE_NO_INDEX); return false; } + if (isOverlap(stationName, targetLine.section)) { + alert(SECTION_DETAIL_WORDS.ALERT_MESSAGE_SECTION_INCLUDES_STATION); + return false; + } return true; } diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index 595589c25..b04dd3275 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -1,6 +1,7 @@ import Component from '../factory/Component.js'; import SectionDetailManager from './SectionDetailManager.js'; import { SECTION_SELECTOR } from '../share/selector.js'; +import { isEmpty } from '../share/utils.js'; export default class SectionManager extends Component { constructor(props) { @@ -40,7 +41,7 @@ export default class SectionManager extends Component { } hideDetailManager() { - if (this.data.lineList.length === 0) { + if (isEmpty(this.data.lineList)) { this.sectionDetailManager.hide(); } } diff --git a/src/managers/StationManager.js b/src/managers/StationManager.js index f468f7b3f..7fff3e87a 100644 --- a/src/managers/StationManager.js +++ b/src/managers/StationManager.js @@ -65,13 +65,11 @@ export default class StationManager extends Component { template() { return this.data.stationList - .map((station, index) => stationTableTemplate( - { - stationName: station, - index, - buttonClass: STATION_SELECTOR.DELETE_BUTTON_CLASS, - }, - )) + .map((station, index) => stationTableTemplate({ + stationName: station, + index, + buttonClass: STATION_SELECTOR.DELETE_BUTTON_CLASS, + })) .join(''); } diff --git a/src/managers/app.js b/src/managers/app.js index 2420dfacd..4124126ca 100644 --- a/src/managers/app.js +++ b/src/managers/app.js @@ -49,15 +49,20 @@ export default class SubwayManager extends Component { const { nodeName } = event.target; const { id } = event.target; if (nodeName !== 'BUTTON') return; - [ + this.getManager(id); + }; + + getManager(id) { + const managerList = [ this.stationManager, this.lineManager, this.sectionManager, this.mapPrintManager, - ].forEach((manager) => { + ]; + managerList.forEach((manager) => { manager.managerId === id ? manager.show() : manager.hide(); }); - }; + } syncData = (data) => { storage.setItem(STORAGE_KEY, data); diff --git a/src/share/utils.js b/src/share/utils.js index b3d8bf6f6..bcd8b00b9 100644 --- a/src/share/utils.js +++ b/src/share/utils.js @@ -4,6 +4,6 @@ export const isValidLength = (value, minLength) => value.length >= minLength; export const isSameStation = (prevStation, nextStation) => prevStation === nextStation; -export const isEmpty = (value) => value === ''; +export const isEmpty = (value) => !value.length; export const deleteWhiteSpace = (words) => words.replaceAll(' ', ''); From 1e1698ad83194b90a17c584d266b0380bb406666 Mon Sep 17 00:00:00 2001 From: nxxc Date: Tue, 15 Dec 2020 20:56:55 +0900 Subject: [PATCH 44/44] =?UTF-8?q?[fix]=20=EA=B5=AC=EA=B0=84=20=EA=B4=80?= =?UTF-8?q?=EB=A6=AC=20=EB=A9=94=EB=89=B4=EB=B2=97=EC=96=B4=EB=82=98?= =?UTF-8?q?=EB=8F=84=20=EA=B7=B8=EB=8C=80=EB=A1=9C=20=EC=9E=88=EB=8D=98=20?= =?UTF-8?q?=EB=B2=84=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 구간관리 메뉴를 벗어났다 다시 돌아와도 선택했던 노선이 그대로 있던버그 수정 - Update README.md --- .vscode/settings.json | 3 --- README.md | 8 +++++--- src/managers/SectionManager.js | 12 +----------- src/managers/app.js | 3 +++ style.css | 10 ++++++++++ 5 files changed, 19 insertions(+), 17 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index aef844305..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "liveServer.settings.port": 5501 -} \ No newline at end of file diff --git a/README.md b/README.md index b0930615f..3f72aab87 100644 --- a/README.md +++ b/README.md @@ -132,9 +132,9 @@ - 공통 기능 - [x] 각 메뉴를 클릭시 해당 기능을 수행할 수 있게해야 한다. (역 관리, 노선 관리, 구간 관리, 지하철 노선도 출력) - - [x] state를 공유할 수 있도록 각 메뉴에서 state를 동기화 시킨다. + - [x] data를 공유할 수 있도록 각 메뉴에서 data를 동기화 시킨다. - [x] localStorage를 이용하여 새로고침해도 최근 데이터를 활용해 목록들을 표시한다. - - [x] form 제출이 input을 초기화 한다. + - [x] form 제출 시 input을 초기화 한다. - [x] 올바르 않은 입력일 경우 경고창을 표시하여 재입력 할 수 있게한다. - 역 관련 기능 @@ -167,7 +167,7 @@ - [x] 새로운 구간 등록시 노선의 상행종점과 하행종점을 업데이트 한다. - [x] 구간 등록시 노선에 이미 포함된 역인지 확인한다. - [x] '노선에서 제거' 버튼 클릭시 노선에서 제거 할 수 있게 해야한다. - - [x] 노선에 포함된 역이 두개 이하인지 확인해야한다. + - [x] 삭제시 노선에 포함된 역이 두개 이하인지 확인해야한다. - [x] 삭제에 성공했을 경우 목록을 업데이트 해서 다시 표시해야 한다. - 노선도 출력 기능 @@ -176,4 +176,6 @@ - 예외사항 - 입력의 모든 공백은 제외한다. + - 노선에 구간 추가 시 현재의 길이보다 더 높은 숫자를 입력한 경우 마지막에 추가된다. + diff --git a/src/managers/SectionManager.js b/src/managers/SectionManager.js index b04dd3275..efe9d44ac 100644 --- a/src/managers/SectionManager.js +++ b/src/managers/SectionManager.js @@ -1,7 +1,6 @@ import Component from '../factory/Component.js'; import SectionDetailManager from './SectionDetailManager.js'; import { SECTION_SELECTOR } from '../share/selector.js'; -import { isEmpty } from '../share/utils.js'; export default class SectionManager extends Component { constructor(props) { @@ -16,8 +15,6 @@ export default class SectionManager extends Component { }); this.sectionLineMenu.addEventListener('click', this.changeSectionDetailManger); - - this.sectionDetailManager.hide(); } changeSectionDetailManger = (event) => { @@ -36,18 +33,11 @@ export default class SectionManager extends Component { updateMenuList() { this.sectionLineMenu.innerHTML = this.data.lineList - .map((line) => ``) + .map((line) => ``) .join(''); } - hideDetailManager() { - if (isEmpty(this.data.lineList)) { - this.sectionDetailManager.hide(); - } - } - render() { - this.hideDetailManager(); this.updateMenuList(); } } diff --git a/src/managers/app.js b/src/managers/app.js index 4124126ca..6ceb2785b 100644 --- a/src/managers/app.js +++ b/src/managers/app.js @@ -61,6 +61,9 @@ export default class SubwayManager extends Component { ]; managerList.forEach((manager) => { manager.managerId === id ? manager.show() : manager.hide(); + manager.managerId === MENU.SECTION_MANAGER_BUTTON_ID + ? this.sectionManager.sectionDetailManager.hide() + : ''; }); } diff --git a/style.css b/style.css index 3debb3c6d..fa27f7831 100644 --- a/style.css +++ b/style.css @@ -9,10 +9,20 @@ td { border: 1px solid black; } +input{ + width: 10rem; +} + li{ list-style :none } .dot{ list-style: disc; +} + +.section-line-menu-button{ + min-width: 3rem; + min-height: 1.5rem; + margin-right: 0.3rem; } \ No newline at end of file
${name}
${stationName}
${name} ${startStation}
${index} ${name}