diff --git a/.eslinrc.json b/.eslinrc.json new file mode 100644 index 000000000..984c2dc7b --- /dev/null +++ b/.eslinrc.json @@ -0,0 +1,16 @@ +{ + "plugins": ["prettier"], + "extends": ["eslint:recommended", "google", "plugin:prettier/recommended"], + "rules": { + "prettier/prettier": "error" + }, + "env": { + "browser": true, + "node": true, + "es2020": true + }, + "parserOptions": { + "ecmaVersion": 11, + "sourceType": "module" + } +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..598d33228 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "tabWidth": 2, + "useTabs": false, + "semi": true, + "bracketSpacing": true, + "printWidth": 80 +} diff --git a/README.md b/README.md index e97a1d649..eafa0409f 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)๋ฅผ ์ด์šฉํ•˜์—ฌ, ์ƒˆ๋กœ๊ณ ์นจํ•˜๋”๋ผ๋„ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ž‘์—…ํ•œ ์ •๋ณด๋“ค์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค.
diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..e3527a893 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,165 @@ +# ๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๋ฏธ์…˜ + +## ๐Ÿ“Œ ํ”„๋กœ์ ํŠธ ๊ฐœ์š” + +์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๋ฏธ์…˜์€ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค. ํ”„๋กœ๊ทธ๋žจ ์ƒ๋‹จ์—๋Š” ์ด 4๊ฐ€์ง€์˜ ๋ฉ”๋‰ด๋กœ `1. ์—ญ ๊ด€๋ฆฌ`, `2. ๋…ธ์„  ๊ด€๋ฆฌ`, `3. ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ`, `4. ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ` ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. `1. ์—ญ ๊ด€๋ฆฌ`, `2. ๋…ธ์„  ๊ด€๋ฆฌ`, `3. ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ` ๋ฉ”๋‰ด๋Š” ๊ฐ๊ฐ ์ง€ํ•˜์ฒ  ์—ญ, ์ง€ํ•˜์ฒ  ๋…ธ์„ , ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์„ ๋“ฑ๋ก(์ถ”๊ฐ€) ํ•˜๊ฑฐ๋‚˜ ์‚ญ์ œ, ์กฐํšŒํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉฐ, `4. ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ` ๋ฉ”๋‰ด๋Š” ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” ๊ธฐ๋Šฅ์„ ํ•ฉ๋‹ˆ๋‹ค. + +## ๐Ÿš€ ๊ธฐ๋Šฅ ์š”๊ตฌ ์‚ฌํ•ญ + +### 1.1 ์ฃผ์–ด์ง„ ์š”๊ตฌ ์‚ฌํ•ญ + +##### ์ง€ํ•˜์ฒ  ์—ญ ๊ด€๋ จ ๊ธฐ๋Šฅ + +- ์ง€ํ•˜์ฒ  ์—ญ์„ ๋“ฑ๋กํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค. (๋‹จ, ๋…ธ์„ ์— ๋“ฑ๋ก๋œ ์—ญ์€ ์‚ญ์ œํ•  ์ˆ˜ ์—†๋‹ค) +- ์ค‘๋ณต๋œ ์ง€ํ•˜์ฒ  ์—ญ ์ด๋ฆ„์ด ๋“ฑ๋ก๋  ์ˆ˜ ์—†๋‹ค. +- ์ง€ํ•˜์ฒ  ์—ญ์€ 2๊ธ€์ž ์ด์ƒ์ด์–ด์•ผ ํ•œ๋‹ค. +- ์ง€ํ•˜์ฒ  ์—ญ์˜ ๋ชฉ๋ก์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. + +##### ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ด€๋ จ ๊ธฐ๋Šฅ + +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ๋“ฑ๋กํ•˜๊ณ  ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค. +- ์ค‘๋ณต๋œ ์ง€ํ•˜์ฒ  ๋…ธ์„  ์ด๋ฆ„์ด ๋“ฑ๋ก๋  ์ˆ˜ ์—†๋‹ค. +- ๋…ธ์„  ๋“ฑ๋ก ์‹œ ์ƒํ–‰ ์ข…์ ์—ญ๊ณผ ํ•˜ํ–‰ ์ข…์ ์—ญ์„ ์ž…๋ ฅ๋ฐ›๋Š”๋‹ค. +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ๋ชฉ๋ก์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. + +##### ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ + +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ์— ๊ตฌ๊ฐ„์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์€ ๋…ธ์„ ์— ์—ญ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ธฐ๋Šฅ์ด๋ผ๊ณ ๋„ ํ•  ์ˆ˜ ์žˆ๋‹ค. + - ์—ญ๊ณผ ์—ญ์‚ฌ์ด๋ฅผ ๊ตฌ๊ฐ„์ด๋ผ ํ•˜๊ณ  ์ด ๊ตฌ๊ฐ„๋“ค์˜ ๋ชจ์Œ์ด ๋…ธ์„ ์ด๋‹ค. +- ํ•˜๋‚˜์˜ ์—ญ์€ ์—ฌ๋Ÿฌ๊ฐœ์˜ ๋…ธ์„ ์— ์ถ”๊ฐ€๋  ์ˆ˜ ์žˆ๋‹ค. +- ์—ญ๊ณผ ์—ญ ์‚ฌ์ด์— ์ƒˆ๋กœ์šด ์—ญ์ด ์ถ”๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. +- ๋…ธ์„ ์—์„œ ๊ฐˆ๋ž˜๊ธธ์€ ์ƒ๊ธธ ์ˆ˜ ์—†๋‹ค. + +##### ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„ ์‚ญ์ œ ๊ธฐ๋Šฅ + +- ๋…ธ์„ ์— ๋“ฑ๋ก๋œ ์—ญ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค. +- ์ข…์ ์„ ์ œ๊ฑฐํ•  ๊ฒฝ์šฐ ๋‹ค์Œ ์—ญ์ด ์ข…์ ์ด ๋œ๋‹ค. +- ๋…ธ์„ ์— ํฌํ•จ๋œ ์—ญ์ด ๋‘๊ฐœ ์ดํ•˜์ผ ๋•Œ๋Š” ์—ญ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์—†๋‹ค. + +##### ์ง€ํ•˜์ฒ  ๋…ธ์„ ์— ๋“ฑ๋ก๋œ ์—ญ ์กฐํšŒ ๊ธฐ๋Šฅ + +- ๋…ธ์„ ์˜ ์ƒํ–‰ ์ข…์ ๋ถ€ํ„ฐ ํ•˜ํ–‰ ์ข…์ ๊นŒ์ง€ ์—ฐ๊ฒฐ๋œ ์ˆœ์„œ๋Œ€๋กœ ์—ญ ๋ชฉ๋ก์„ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค. + +### 1.2 ๊ธฐ๋Šฅ ๋ชฉ๋ก + +- [x] `1. ์—ญ ๊ด€๋ฆฌ`, `2. ๋…ธ์„  ๊ด€๋ฆฌ`, `3. ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ`, `4. ์ง€ํ•˜์ฒ  ๋…ธ์„  ์ถœ๋ ฅ` ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ๊ด€๋ จ ํ™”๋ฉด์„ ์ถœ๋ ฅํ•œ๋‹ค. +- ์—ญ ๊ด€๋ฆฌ + - [x] `localStorage` ๋ฐ `data`์†์„ฑ์„ ๋ฐ˜์˜ํ•œ๋‹ค. + - [x] ์ง€ํ•˜์ฒ  ์—ญ ๋ชฉ๋ก์„ ์กฐํšŒํ•œ๋‹ค. + - `์—ญ ์ถ”๊ฐ€` + - [x] ์ž…๋ ฅํ•œ ์—ญ ์ด๋ฆ„์ด 2๊ธ€์ž ์ด์ƒ์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ์ž…๋ ฅํ•œ ์—ญ ์ด๋ฆ„์ด ์ค‘๋ณต์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ์ง€ํ•˜์ฒ  ์—ญ ๋ชฉ๋ก์— ๋ฐ˜์˜ํ•œ๋‹ค. + - `์‚ญ์ œ` + - [x] `alert`๋ฅผ ํ†ตํ•ด ๋‹ค์‹œ ๋ฌผ์–ด๋ณธ๋‹ค. + - [x] ์ง€ํ•˜์ฒ  ์—ญ ๋ชฉ๋ก์— ๋ฐ˜์˜ํ•œ๋‹ค. + - [x] ๋ˆ„๋ฅธ ๊ณณ์ด ๋ฒ„ํŠผ์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ๋…ธ์„ (์ „์ฒด ๊ตฌ๊ฐ„)์— ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. +- ๋…ธ์„  ๊ด€๋ฆฌ + - [x] ๋…ธ์„  ๋ชฉ๋ก์„ ์กฐํšŒํ•œ๋‹ค. + - `๋…ธ์„  ์ถ”๊ฐ€` + - [x] ์ƒํ–‰ ์ข…์ ๊ณผ ํ•˜ํ–‰ ์ข…์  ๋ชฉ๋ก์„ ์กฐํšŒํ•œ๋‹ค. + - [x] ์ž…๋ ฅํ•œ ๋…ธ์„  ์ด๋ฆ„์ด ์ค‘๋ณต์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ๋…ธ์„ ์˜ ์ƒํ–‰ ์ข…์ ๊ณผ ํ•˜ํ–‰ ์ข…์ ์ด ๋™์ผํ•œ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ๋…ธ์„ ์˜ ์ด๋ฆ„์ด ๋‹ฌ๋ผ๋„ ์ƒํ–‰ ์ข…์  ๋˜๋Š” ํ•˜ํ–‰ ์ข…์ ์ด ์ค‘๋ณต๋  ์ˆ˜ ์—†๋‹ค. + - [x] ์ƒํ–‰ ์ข…์ ์ด ์ค‘๋ณต์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ํ•˜ํ–‰ ์ข…์ ์ด ์ค‘๋ณต์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ์ƒํ–‰ ์ข…์ ๊ณผ ํ•˜ํ–‰ ์ข…์ ์˜ ๋ฐฉํ–ฅ์ด ๋ฐ˜๋Œ€์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ๋…ธ์„  ๋ชฉ๋ก์— ๋ฐ˜์˜ํ•œ๋‹ค. + - `์‚ญ์ œ` + - [x] `alert`๋ฅผ ํ†ตํ•ด ๋‹ค์‹œ ๋ฌผ์–ด๋ณธ๋‹ค. + - [x] ๋…ธ์„  ๋ชฉ๋ก์— ๋ฐ˜์˜ํ•œ๋‹ค. + - [x] ๋ˆ„๋ฅธ ๊ณณ์ด ๋ฒ„ํŠผ์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. +- ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ + - [x] ๊ตฌ๊ฐ„์„ ์ˆ˜์ •ํ•  ๋…ธ์„ ์˜ ๋ชฉ๋ก์„ ์กฐํšŒํ•œ๋‹ค. (๋ฒ„ํŠผ์œผ๋กœ ์ถœ๋ ฅ) + - [x] ๋…ธ์„ ์„ ์„ ํƒํ•˜๋ฉด ํ•ด๋‹น ๋…ธ์„ ์˜ ๊ตฌ๊ฐ„ ๋ชฉ๋ก์„ ์กฐํšŒํ•œ๋‹ค. + - [x] ์ œ๋ชฉ์€ `(์„ ํƒ๋œ ๋…ธ์„ ) ๊ด€๋ฆฌ`๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. + - [x] ๋ˆ„๋ฅธ ๊ณณ์ด ๋ฒ„ํŠผ์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - `๋“ฑ๋ก` + - [x] ์ž…๋ ฅํ•œ ์—ญ์˜ ์ด๋ฆ„๊ณผ ์ˆœ์„œ๋ฅผ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ์ž…๋ ฅํ•œ ์—ญ์˜ ์ด๋ฆ„์ด ์ค‘๋ณต์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ์—ญ๊ณผ ์—ญ ์‚ฌ์ด(๊ตฌ๊ฐ„)์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. + - [x] ๊ตฌ๊ฐ„ ๋ชฉ๋ก์— ๋ฐ˜์˜ํ•œ๋‹ค. + - `๋…ธ์„ ์—์„œ ์ œ๊ฑฐ` + - [x] ๋…ธ์„ ์— ๋“ฑ๋ก๋œ ์—ญ์ด ๋‘ ๊ฐœ ์ดํ•˜์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. (๋‘ ๊ฐœ ์ดํ•˜์ธ ๊ฒฝ์šฐ์—๋Š” ์‚ญ์ œ ๋ถˆ๊ฐ€) + - [x] `alert`๋ฅผ ํ†ตํ•ด ๋‹ค์‹œ ๋ฌผ์–ด๋ณธ๋‹ค. + - [x] ๊ตฌ๊ฐ„ ๋ชฉ๋ก์— ๋ฐ˜์˜ํ•œ๋‹ค. + - [x] ๋ˆ„๋ฅธ ๊ณณ์ด ๋ฒ„ํŠผ์ธ์ง€ ๊ฒ€์ฆํ•ด์•ผ ํ•œ๋‹ค. +- ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ + - [x] ๊ฐ ๋…ธ์„ ์˜ ์—ญ๋“ค์„ ์กฐํšŒํ•œ๋‹ค. + +
+ +## โœ… ๋น„๊ธฐ๋Šฅ ์š”๊ตฌ์‚ฌํ•ญ + +### 2.1 ์†์„ฑ ํƒœ๊ทธ ์š”๊ตฌ์‚ฌํ•ญ + +##### ๋ฉ”๋‰ด ๋ฒ„ํŠผ + +- [x] ์—ญ ๊ด€๋ฆฌ button ํƒœ๊ทธ๋Š” `#station-manager-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ๋…ธ์„  ๊ด€๋ฆฌ button ํƒœ๊ทธ๋Š” `#line-manager-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ button ํƒœ๊ทธ๋Š” `#section-manager-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ ๊ด€๋ฆฌ button ํƒœ๊ทธ๋Š” `#map-print-manager-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. + +##### ์ง€ํ•˜์ฒ  ์—ญ ๊ด€๋ จ ๊ธฐ๋Šฅ + +- [x] ์ง€ํ•˜์ฒ  ์—ญ์„ ์ž…๋ ฅํ•˜๋Š” input ํƒœ๊ทธ๋Š” `#station-name-input` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ์—ญ์„ ์ถ”๊ฐ€ํ•˜๋Š” button ํƒœ๊ทธ๋Š” `#station-add-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ์—ญ์„ ์‚ญ์ œํ•˜๋Š” button ํƒœ๊ทธ๋Š” `.station-delete-button` class๊ฐ’์„ ๊ฐ€์ง„๋‹ค. + +##### ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ด€๋ จ ๊ธฐ๋Šฅ + +- [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ์ด๋ฆ„์„ ์ž…๋ ฅํ•˜๋Š” input ํƒœ๊ทธ๋Š” `#line-name-input` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ์ƒํ–‰ ์ข…์ ์„ ์„ ํƒํ•˜๋Š” select ํƒœ๊ทธ๋Š” `#line-start-station-selector` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ์˜ ํ•˜ํ–‰ ์ข…์ ์„ ์„ ํƒํ•˜๋Š” select ํƒœ๊ทธ๋Š” `#line-end-station-selector` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ์ถ”๊ฐ€ํ•˜๋Š” button ํƒœ๊ทธ๋Š” `#line-add-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ์‚ญ์ œํ•˜๋Š” button ํƒœ๊ทธ๋Š” `.line-delete-button` class๊ฐ’์„ ๊ฐ€์ง„๋‹ค. + +##### ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ + +- [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ์„ ์„ ํƒํ•˜๋Š” button ํƒœ๊ทธ๋Š” `.section-line-menu-button` class๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์„ ์„ค์ •ํ•  ์—ญ select ํƒœ๊ทธ๋Š” `#section-station-selector` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์˜ ์ˆœ์„œ๋ฅผ ์ž…๋ ฅํ•˜๋Š” input ํƒœ๊ทธ๋Š” `#section-order-input` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์„ ๋“ฑ๋กํ•˜๋Š” button ํƒœ๊ทธ๋Š” `#section-add-button` id๊ฐ’์„ ๊ฐ€์ง„๋‹ค. +- [x] ์ง€ํ•˜์ฒ  ๊ตฌ๊ฐ„์„ ์ œ๊ฑฐํ•˜๋Š” button ํƒœ๊ทธ๋Š” `.section-delete-button` class๊ฐ’์„ ๊ฐ€์ง„๋‹ค. + +##### ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ ๊ธฐ๋Šฅ + +- [x] ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ์ถœ๋ ฅ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด `
` ํƒœ๊ทธ๋ฅผ ๋งŒ๋“ค๊ณ  ํ•ด๋‹น ํƒœ๊ทธ ๋‚ด๋ถ€์— ๋…ธ์„ ๋„๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค. + +### 2.2 ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์š”๊ตฌ์‚ฌํ•ญ + +##### ๊ธฐ์กด ์š”๊ตฌ์‚ฌํ•ญ + +- ์‚ฌ์šฉ์ž๊ฐ€ ์ž˜๋ชป๋œ ์ž…๋ ฅ ๊ฐ’์„ ์ž‘์„ฑํ•œ ๊ฒฝ์šฐ `alert`์„ ์ด์šฉํ•ด ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ , ์žฌ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. +- ์™ธ๋ถ€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ(jQuery, Lodash ๋“ฑ)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ , ์ˆœ์ˆ˜ Vanilla JS๋กœ๋งŒ ๊ตฌํ˜„ํ•œ๋‹ค. +- **์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ ์ปจ๋ฒค์…˜์„ ์ง€ํ‚ค๋ฉด์„œ ํ”„๋กœ๊ทธ๋ž˜๋ฐ** ํ•œ๋‹ค +- **indent(์ธ๋ดํŠธ, ๋“ค์—ฌ์“ฐ๊ธฐ) depth๋ฅผ 3์ด ๋„˜์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. 2๊นŒ์ง€๋งŒ ํ—ˆ์šฉ**ํ•œ๋‹ค. +- **ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์†Œ๋“œ)์˜ ๊ธธ์ด๊ฐ€ 15๋ผ์ธ์„ ๋„˜์–ด๊ฐ€์ง€ ์•Š๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค.** + - ํ•จ์ˆ˜(๋˜๋Š” ๋ฉ”์†Œ๋“œ)๊ฐ€ ํ•œ ๊ฐ€์ง€ ์ผ๋งŒ ์ž˜ ํ•˜๋„๋ก ๊ตฌํ˜„ํ•œ๋‹ค. +- ๋ณ€์ˆ˜ ์„ ์–ธ์‹œ `var` ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค. `const` ์™€ `let` ์„ ์‚ฌ์šฉํ•œ๋‹ค. +- `import` ๋ฌธ์„ ์ด์šฉํ•ด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋ชจ๋“ˆํ™”ํ•˜๊ณ  ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ ๋‹ค. +- `template literal`์„ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ์™€ html string์„ ๊ฐ€๋…์„ฑ ์ข‹๊ฒŒ ํ‘œํ˜„ํ•œ๋‹ค. + +#### ์ถ”๊ฐ€๋œ ์š”๊ตฌ์‚ฌํ•ญ + +- [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)๋ฅผ ์ด์šฉํ•˜์—ฌ, ์ƒˆ๋กœ๊ณ ์นจํ•˜๋”๋ผ๋„ ๊ฐ€์žฅ ์ตœ๊ทผ์— ์ž‘์—…ํ•œ ์ •๋ณด๋“ค์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค. + +## ๐Ÿ’ป ํ”„๋กœ๊ทธ๋žจ ์‹คํ–‰ ๊ฒฐ๊ณผ + +### ์—ญ๊ด€๋ฆฌ + + + +### ๋…ธ์„ ๊ด€๋ฆฌ + + + +### ๊ตฌ๊ฐ„๊ด€๋ฆฌ + + + +### ๋…ธ์„ ๋„ ์ถœ๋ ฅ + + diff --git a/index.html b/index.html index fc99deac2..d2cda19c3 100644 --- a/index.html +++ b/index.html @@ -2,12 +2,101 @@ + ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ
-

๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ

+

๐Ÿš‡ ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ

+ + + +
+ + +
+
+ +
+ + + +

๐Ÿš‰ ์ง€ํ•˜์ฒ  ์—ญ ๋ชฉ๋ก

+ + + + + + + + +
์—ญ ์ด๋ฆ„์„ค์ •
+
+ + +
+
+ +
+ +
+
+ + +
+
+ + +
+
+ + +

๐Ÿš‰ ์ง€ํ•˜์ฒ  ๋…ธ์„  ๋ชฉ๋ก

+ + + + + + + + + + +
๋…ธ์„  ์ด๋ฆ„์ƒํ–‰ ์ข…์ ์—ญํ•˜ํ–‰ ์ข…์ ์—ญ์„ค์ •
+
+ + +
+

๊ตฌ๊ฐ„์„ ์ˆ˜์ •ํ•  ๋…ธ์„ ์„ ์„ ํƒํ•ด์ฃผ์„ธ์š”.

+
+ +
+

+

๊ตฌ๊ฐ„ ๋“ฑ๋ก

+ + + + + + + + + + + + +
์ˆœ์„œ์ด๋ฆ„์„ค์ •
+
+
+ + +
+ diff --git a/src/controller/line-manager.js b/src/controller/line-manager.js new file mode 100644 index 000000000..a55410ce7 --- /dev/null +++ b/src/controller/line-manager.js @@ -0,0 +1,58 @@ +import { Line, LineObject } from "../model/line.js"; +import { Station } from "../model/station.js"; +import { ConfirmMessage, Constant } from "../util/constant.js"; +import { Storage } from "../util/storage.js"; +import { LineValidation } from "../util/validation.js"; +import { Element, ElementControl } from "../view/element.js"; +import { LineView } from "../view/line-view.js"; + +export const LineManager = { + isVisited: false, + + init() { + this.isVisited = true; + Station.stations = Storage.load(Station.key) + ? Storage.load(Station.key) + : []; + Line.lines = Storage.load(Line.key) ? Storage.load(Line.key) : []; + LineView.render(); + this.setEventListener(); + }, + + setEventListener() { + Element.lineAddButton.addEventListener(Constant.CLICK, () => { + this.onClickAddButton(); + }); + + Element.lineContainer + .querySelector(Constant.TBODY) + .addEventListener(Constant.CLICK, (e) => { + this.onClickDeleteButton(e); + }); + }, + + onClickAddButton() { + const name = Element.lineNameInput.value; + const start = Element.lineStartStationSelector.value; + const end = Element.lineEndStationSelector.value; + + if (LineValidation.isValidLine(name, start, end)) { + Line.add(new LineObject(name, start, end)); + } + LineView.render(); + ElementControl.clearInput(Element.lineNameInput); + }, + + onClickDeleteButton(e) { + const name = e.target.dataset.name; + + if (e.target.tagName !== Constant.BUTTON) { + return; + } + + if (confirm(ConfirmMessage.CHECK_DELETION)) { + Line.delete(name); + LineView.render(); + } + }, +}; diff --git a/src/controller/map-print-manager.js b/src/controller/map-print-manager.js new file mode 100644 index 000000000..b91ab826c --- /dev/null +++ b/src/controller/map-print-manager.js @@ -0,0 +1,17 @@ +import { Line } from "../model/line.js"; +import { Station } from "../model/station.js"; +import { Storage } from "../util/storage.js"; +import { MapPrintView } from "../view/map-print-view.js"; + +export const MapPrintManager = { + isVisited: false, + + init() { + this.isVisited = true; + Station.stations = Storage.load(Station.key) + ? Storage.load(Station.key) + : []; + Line.lines = Storage.load(Line.key) ? Storage.load(Line.key) : []; + MapPrintView.render(); + }, +}; diff --git a/src/controller/section-manager.js b/src/controller/section-manager.js new file mode 100644 index 000000000..3c7884c3f --- /dev/null +++ b/src/controller/section-manager.js @@ -0,0 +1,76 @@ +import { Line } from "../model/line.js"; +import { Section } from "../model/section.js"; +import { Station } from "../model/station.js"; +import { ConfirmMessage, Constant, ErrorMessage } from "../util/constant.js"; +import { Storage } from "../util/storage.js"; +import { SectionValidation } from "../util/validation.js"; +import { Element, ElementControl } from "../view/element.js"; +import { SectionView } from "../view/section-view.js"; + +export const SectionManager = { + isVisited: false, + selectedLine: "", + + init() { + this.isVisited = true; + Station.stations = Storage.load(Station.key) + ? Storage.load(Station.key) + : []; + Line.lines = Storage.load(Line.key) ? Storage.load(Line.key) : []; + SectionView.render(); + this.setEventListener(); + }, + + setEventListener() { + Element.sectionLineMenu.addEventListener(Constant.CLICK, (e) => { + this.onClickLineButton(e); + }); + + Element.sectionAddButton.addEventListener(Constant.CLICK, () => { + this.onClickAddButton(); + }); + + Element.sectionContainer + .querySelector(Constant.TBODY) + .addEventListener(Constant.CLICK, (e) => { + this.onClickDeleteButton(e); + }); + }, + + onClickLineButton(e) { + if (e.target.tagName !== Constant.BUTTON) { + return false; + } + this.selectedLine = e.target.dataset.name; + SectionView.renderSectionManager(this.selectedLine); + }, + + onClickAddButton() { + const station = Element.sectionStationSelector.value; + const order = Element.sectionOrderInupt.value; + + if (SectionValidation.isValidSection(station, order, this.selectedLine)) { + Section.add(station, order, this.selectedLine); + } + SectionView.renderSectionManager(this.selectedLine); + ElementControl.clearInput(Element.sectionOrderInupt); + }, + + onClickDeleteButton(e) { + const idx = e.target.dataset.idx; + + if (e.target.tagName !== Constant.BUTTON) { + return; + } + + if (confirm(ConfirmMessage.CHECK_DELETION_FROM_LINE)) { + if (!SectionValidation.hasMinimumStations(this.selectedLine)) { + alert(ErrorMessage.MINIMUM_STATIONS); + + return; + } + Section.delete(idx, this.selectedLine); + SectionView.renderSectionManager(this.selectedLine); + } + }, +}; diff --git a/src/controller/station-manager.js b/src/controller/station-manager.js new file mode 100644 index 000000000..bef65abd3 --- /dev/null +++ b/src/controller/station-manager.js @@ -0,0 +1,61 @@ +import { Line } from "../model/line.js"; +import { Station } from "../model/station.js"; +import { ConfirmMessage, Constant, ErrorMessage } from "../util/constant.js"; +import { Storage } from "../util/storage.js"; +import { StationValidation } from "../util/validation.js"; +import { Element, ElementControl } from "../view/element.js"; +import { StationView } from "../view/station-view.js"; + +export const StationManager = { + isVisited: false, + + init() { + this.isVisited = true; + Station.stations = Storage.load(Station.key) + ? Storage.load(Station.key) + : []; + Line.lines = Storage.load(Line.key) ? Storage.load(Line.key) : []; + StationView.render(); + this.setEventListener(); + }, + + setEventListener() { + Element.stationAddButton.addEventListener(Constant.CLICK, () => { + this.onClickAddButton(); + }); + + Element.stationContainer + .querySelector(Constant.TBODY) + .addEventListener(Constant.CLICK, (e) => { + this.onClickDeleteButton(e); + }); + }, + + onClickAddButton() { + const name = Element.stationNameInput.value; + + if (StationValidation.isValidStation(name)) { + Station.add(name); + StationView.render(); + } + ElementControl.clearInput(Element.stationNameInput); + }, + + onClickDeleteButton(e) { + const name = e.target.dataset.name; + + if (e.target.tagName !== Constant.BUTTON) { + return; + } + + if (confirm(ConfirmMessage.CHECK_DELETION)) { + if (!StationValidation.isValidStatonDeletion(name)) { + alert(ErrorMessage.STATION_RELATED_LINE); + + return; + } + Station.delete(name); + StationView.render(); + } + }, +}; diff --git a/src/index.js b/src/index.js index e69de29bb..d0b94168c 100644 --- a/src/index.js +++ b/src/index.js @@ -0,0 +1,26 @@ +import { Constant } from "./util/constant.js"; +import { Element, ElementControl } from "./view/element.js"; + +const App = () => { + SubwayManager(); +}; + +const SubwayManager = () => { + Element.stationManagerButton.addEventListener(Constant.CLICK, () => { + ElementControl.showStationContainer(); + }); + + Element.lineManagerButton.addEventListener(Constant.CLICK, () => { + ElementControl.showLineContainer(); + }); + + Element.sectionManagerButton.addEventListener(Constant.CLICK, () => { + ElementControl.showSectionContainer(); + }); + + Element.mapPrintManagerButton.addEventListener(Constant.CLICK, () => { + ElementControl.showMapPrintContainer(); + }); +}; + +App(); diff --git a/src/model/line.js b/src/model/line.js new file mode 100644 index 000000000..44f0871b3 --- /dev/null +++ b/src/model/line.js @@ -0,0 +1,24 @@ +import { Constant } from "../util/constant.js"; +import { Storage } from "../util/storage.js"; + +export class LineObject { + constructor(name, start, end) { + this.name = name; + this.stations = [start, end]; + } +} + +export const Line = { + key: Constant.STORAGE_KEY_LINE, + lines: [], + + add(lineObject) { + this.lines.push(lineObject); + Storage.save(this.key, this.lines); + }, + + delete(name) { + this.lines = this.lines.filter((el) => el.name !== name); + Storage.save(this.key, this.lines); + }, +}; diff --git a/src/model/section.js b/src/model/section.js new file mode 100644 index 000000000..c1c4c9484 --- /dev/null +++ b/src/model/section.js @@ -0,0 +1,20 @@ +import { Storage } from "../util/storage.js"; +import { Line } from "./line.js"; + +export const Section = { + add(station, order, line) { + const stationArray = Line.lines.filter(({ name }) => name === line)[0] + .stations; + + stationArray.splice(order, 0, station); + Storage.save(Line.key, Line.lines); + }, + + delete(idx, line) { + const stationArray = Line.lines.filter(({ name }) => name === line)[0] + .stations; + + stationArray.splice(idx, 1); + Storage.save(Line.key, Line.lines); + }, +}; diff --git a/src/model/station.js b/src/model/station.js new file mode 100644 index 000000000..9b4cc279b --- /dev/null +++ b/src/model/station.js @@ -0,0 +1,17 @@ +import { Constant } from "../util/constant.js"; +import { Storage } from "../util/storage.js"; + +export const Station = { + key: Constant.STORAGE_KEY_STATION, + stations: [], + + add(name) { + this.stations.push(name); + Storage.save(this.key, this.stations); + }, + + delete(name) { + this.stations = this.stations.filter((e) => e !== name); + Storage.save(this.key, this.stations); + }, +}; diff --git a/src/util/constant.js b/src/util/constant.js new file mode 100644 index 000000000..d76025eab --- /dev/null +++ b/src/util/constant.js @@ -0,0 +1,71 @@ +export const Constant = { + // ์ดˆ๊ธฐ ํ™”๋ฉด ๋ฒ„ํŠผ + STATION_MANAGER_BTN_ID: "#station-manager-button", + LINE_MANAGER_BTN_ID: "#line-manager-button", + SECTION_MANAGER_BTN_ID: "#section-manager-button", + MAP_PRINT_MANAGER_BTN_ID: "#map-print-manager-button", + + // ์—ญ ๊ด€๋ฆฌ + STATION_CONTAINER_CLASS: ".station-container", + STORAGE_KEY_STATION: "stations", + STATION_ADD_BUTTON_ID: "#station-add-button", + STATION_NAME_INPUT_ID: "#station-name-input", + STATION_DELELE_BUTTON_CLASS: ".station-delete-button", + + // ๋…ธ์„  ๊ด€๋ฆฌ + LINE_CONTAINER_CLASS: ".line-container", + STORAGE_KEY_LINE: "lines", + LINE_START_STATION_SELECTOR_ID: "#line-start-station-selector", + LINE_END_STATION_SELECTOR_ID: "#line-end-station-selector", + LINE_ADD_BUTTON_ID: "#line-add-button", + LINE_NAME_INPUT_ID: "#line-name-input", + + // ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ + SECTION_CONTAINER_CLASS: ".section-container", + SECTION_LINE_MENU_CLASS: ".section-line-menu", + SECTION_MANAGER_CLASS: ".section-manager", + SECTION_MANAGER_TITLE_CLASS: ".section-manager-title", + SECTION_STATION_SELECTOR_ID: "#section-station-selector", + SECTION_ADD_BUTTON_ID: "#section-add-button", + SECTION_ORDER_INPUT_ID: "#section-order-input", + + // ์ง€ํ•˜์ฒ  ๋…ธ์„  ๊ด€๋ฆฌ + MAP_PRINT_CONTAINER_CLASS: ".map-print-container", + + // validation + MINIMUM_LENGTH: 2, + REGEX_CATCHING_WHITESPACE: /^\s*$/, + REGEX_CATCHING_INTEGER: /^[0-9 ()+-]+$/, + + // tag ๊ด€๋ จ + CLICK: "click", + NONE: "none", + BLOCK: "block", + TBODY: "tbody", + BUTTON: "BUTTON", +}; + +export const ErrorMessage = { + // ๊ณตํ†ต + DUPLICATED_STATION_NAME: "์ค‘๋ณต๋˜์ง€ ์•Š์€ ์—ญ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + + // ์—ญ ๊ด€๋ฆฌ + MINIMUM_NAME_LENGTH: "๊ณต๋ฐฑ์ด ์•„๋‹Œ 2๊ธ€์ž ์ด์ƒ์˜ ์—ญ ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + STATION_RELATED_LINE: "๋…ธ์„ ์— ํฌํ•จ๋œ ์—ญ์€ ์ œ๊ฑฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", + + // ๋…ธ์„  ๊ด€๋ฆฌ + NAME_WHITE_SPACE: "๊ณต๋ฐฑ์ด ์•„๋‹Œ ๋…ธ์„  ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + SAME_START_END_STATION: "์„œ๋กœ ๋‹ค๋ฅธ ์ข…์ ์„ ์„ ํƒํ•ด ์ฃผ์„ธ์š”.", + DUPLICATED_START_END_STATION: "๊ธฐ์กด ๋…ธ์„ ๊ณผ ๋‹ค๋ฅธ ์ƒํ–‰, ํ•˜ํ–‰ ์ข…์ ์„ ์„ ํƒํ•ด ์ฃผ์„ธ์š”.\n๋˜ํ•œ, ์ข…์  ๋ฐฉํ–ฅ๋งŒ ๋‹ค๋ฅธ ๊ฒฝ์šฐ ๋™์ผํ•œ ๋…ธ์„ ์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค.", + DUPLICATED_LINE_NAME: "์ค‘๋ณต๋˜์ง€ ์•Š์€ ๋…ธ์„  ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + + // ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ + NOT_INTEGER_ORDER: "1 ์ด์ƒ ์ •์ˆ˜์˜ ์ˆœ์„œ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + MINIMUM_ORDER: "1 ์ด์ƒ์˜ ์ˆœ์„œ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.", + MINIMUM_STATIONS: "๋…ธ์„ ์— ํฌํ•จ๋œ ์—ญ์ด ๋‘๊ฐœ ์ดํ•˜์ผ ๋•Œ๋Š” ์—ญ์„ ์ œ๊ฑฐํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.", +}; + +export const ConfirmMessage = { + CHECK_DELETION: "์ •๋ง๋กœ ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?", + CHECK_DELETION_FROM_LINE: "์ •๋ง๋กœ ๋…ธ์„ ์—์„œ ์‚ญ์ œํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?", +}; diff --git a/src/util/storage.js b/src/util/storage.js new file mode 100644 index 000000000..3df31279b --- /dev/null +++ b/src/util/storage.js @@ -0,0 +1,9 @@ +export const Storage = { + save(key, array) { + localStorage.setItem(key, JSON.stringify(array)); + }, + + load(key) { + return JSON.parse(localStorage.getItem(key)); + }, +}; diff --git a/src/util/validation.js b/src/util/validation.js new file mode 100644 index 000000000..dc8e6afbb --- /dev/null +++ b/src/util/validation.js @@ -0,0 +1,186 @@ +import { Line } from "../model/line.js"; +import { Station } from "../model/station.js"; +import { Constant, ErrorMessage } from "./constant.js"; + +export const StationValidation = { + isValidStation(name) { + return this.hasValidName(name); + }, + + hasValidName(name) { + if (!this.hasMinimumLength(name)) { + alert(ErrorMessage.MINIMUM_NAME_LENGTH); + + return; + } + + if (!this.isNotDuplicated(name)) { + alert(ErrorMessage.DUPLICATED_STATION_NAME); + + return; + } + + return true; + }, + + hasMinimumLength(name) { + return ( + name.length >= Constant.MINIMUM_LENGTH && + !Constant.REGEX_CATCHING_WHITESPACE.test(name) + ); + }, + + isNotDuplicated(name) { + return !Station.stations.includes(name); + }, + + isValidStatonDeletion(station) { + let isValid = true; + + Line.lines.forEach(({ stations }) => { + if (stations.includes(station)) { + isValid = false; + } + }); + + return isValid; + }, +}; + +export const LineValidation = { + isValidLine(name, start, end) { + return this.hasValidName(name) && this.hasValidStartEndStations(start, end); + }, + + hasValidName(name) { + if (!this.isNotWhiteSpace(name)) { + alert(ErrorMessage.NAME_WHITE_SPACE); + + return; + } + + if (!this.isNotDuplicated(name)) { + alert(ErrorMessage.DUPLICATED_LINE_NAME); + + return; + } + + return true; + }, + + hasValidStartEndStations(start, end) { + if (this.isSameStartEndStation(start, end)) { + alert(ErrorMessage.SAME_START_END_STATION); + + return; + } + + if (this.isDuplicatedStartEndStation(start, end)) { + alert(ErrorMessage.DUPLICATED_START_END_STATION); + + return; + } + + return true; + }, + + isNotWhiteSpace(name) { + return !Constant.REGEX_CATCHING_WHITESPACE.test(name); + }, + + isNotDuplicated(name) { + const stationNameArray = Line.lines.map(({ name }) => name); + + return !stationNameArray.includes(name); + }, + + isSameStartEndStation(start, end) { + return start === end; + }, + + isDuplicatedStartEndStation(start, end) { + let isValid = false; + + Line.lines.forEach(({ stations }) => { + if (stations[0] === start) { + isValid = true; + } + if (stations[stations.length - 1] === end) { + isValid = true; + } + if (stations[0] === end && stations[stations.length - 1] === start) { + isValid = true; + } + }); + + return isValid; + } +}; + +export const SectionValidation = { + isValidSection(station, order, selectedLine) { + return ( + this.hasValidName(station, selectedLine) && + this.hasValidOrder(order, selectedLine) + ); + }, + + hasValidName(station, selectedLine) { + if (!this.isNotDuplicated(station, selectedLine)) { + alert(ErrorMessage.DUPLICATED_STATION_NAME); + + return; + } + + return true; + }, + + hasValidOrder(order, selectedLine) { + const stationArray = Line.lines.filter( + ({ name }) => name === selectedLine + )[0].stations; + + if (!Constant.REGEX_CATCHING_INTEGER.test(order)) { + alert(ErrorMessage.NOT_INTEGER_ORDER); + + return; + } + + if (!this.hasValidNumberRange(order, stationArray)) { + return; + } + + return true; + }, + + hasValidNumberRange(order, stationArray) { + if (order < 1) { + alert(ErrorMessage.MINIMUM_ORDER); + + return; + } + + if (order > stationArray.length - 1) { + alert(`${stationArray.length - 1} ์ดํ•˜์˜ ์ˆœ์„œ๋ฅผ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.`); + + return; + } + + return true; + }, + + isNotDuplicated(station, selectedLine) { + const stationArray = Line.lines.filter( + ({ name }) => name === selectedLine + )[0].stations; + + return !stationArray.includes(station); + }, + + hasMinimumStations(selectedLine) { + return ( + Line.lines.filter(({ name }) => name === selectedLine)[0].stations + .length > Constant.MINIMUM_LENGTH + ); + }, +}; diff --git a/src/view/element.js b/src/view/element.js new file mode 100644 index 000000000..4fe778790 --- /dev/null +++ b/src/view/element.js @@ -0,0 +1,103 @@ +import { StationManager } from "../controller/station-manager.js"; +import { StationView } from "./station-view.js"; +import { Constant } from "../util/constant.js"; +import { LineManager } from "../controller/line-manager.js"; +import { LineView } from "./line-view.js"; +import { SectionManager } from "../controller/section-manager.js"; +import { SectionView } from "./section-view.js"; +import { MapPrintView } from "./map-print-view.js"; +import { MapPrintManager } from "../controller/map-print-manager.js"; + +export const Element = { + // ์ดˆ๊ธฐ ํ™”๋ฉด ๋ฒ„ํŠผ + stationManagerButton: document.querySelector(Constant.STATION_MANAGER_BTN_ID), + lineManagerButton: document.querySelector(Constant.LINE_MANAGER_BTN_ID), + sectionManagerButton: document.querySelector(Constant.SECTION_MANAGER_BTN_ID), + mapPrintManagerButton: document.querySelector( + Constant.MAP_PRINT_MANAGER_BTN_ID + ), + + // ์—ญ ๊ด€๋ฆฌ + stationContainer: document.querySelector(Constant.STATION_CONTAINER_CLASS), + stationAddButton: document.querySelector(Constant.STATION_ADD_BUTTON_ID), + stationNameInput: document.querySelector(Constant.STATION_NAME_INPUT_ID), + stationDeleteButton: document.querySelector( + Constant.STATION_DELELE_BUTTON_CLASS + ), + + // ๋…ธ์„  ๊ด€๋ฆฌ + lineContainer: document.querySelector(Constant.LINE_CONTAINER_CLASS), + lineStartStationSelector: document.querySelector( + Constant.LINE_START_STATION_SELECTOR_ID + ), + lineEndStationSelector: document.querySelector( + Constant.LINE_END_STATION_SELECTOR_ID + ), + lineAddButton: document.querySelector(Constant.LINE_ADD_BUTTON_ID), + lineNameInput: document.querySelector(Constant.LINE_NAME_INPUT_ID), + + // ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ + sectionContainer: document.querySelector(Constant.SECTION_CONTAINER_CLASS), + sectionLineMenu: document.querySelector(Constant.SECTION_LINE_MENU_CLASS), + sectionManager: document.querySelector(Constant.SECTION_MANAGER_CLASS), + sectionManagerTitle: document.querySelector( + Constant.SECTION_MANAGER_TITLE_CLASS + ), + sectionStationSelector: document.querySelector( + Constant.SECTION_STATION_SELECTOR_ID + ), + sectionAddButton: document.querySelector(Constant.SECTION_ADD_BUTTON_ID), + sectionOrderInupt: document.querySelector(Constant.SECTION_ORDER_INPUT_ID), + + // ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ + mapPrintContainer: document.querySelector(Constant.MAP_PRINT_CONTAINER_CLASS), +}; + +export const ElementControl = { + hideAllContainers() { + Element.stationContainer.style.display = Constant.NONE; + Element.lineContainer.style.display = Constant.NONE; + Element.sectionContainer.style.display = Constant.NONE; + Element.mapPrintContainer.style.display = Constant.NONE; + }, + + showStationContainer() { + this.hideAllContainers(); + Element.stationContainer.style.display = Constant.BLOCK; + + StationManager.isVisited ? StationView.render() : StationManager.init(); + }, + + showLineContainer() { + this.hideAllContainers(); + Element.lineContainer.style.display = Constant.BLOCK; + + LineManager.isVisited ? LineView.render() : LineManager.init(); + }, + + showSectionContainer() { + this.hideAllContainers(); + Element.sectionContainer.style.display = Constant.BLOCK; + + SectionManager.isVisited ? SectionView.render() : SectionManager.init(); + }, + + showSectionManager() { + Element.sectionManager.style.display = Constant.BLOCK; + }, + + hideSectionManager() { + Element.sectionManager.style.display = Constant.NONE; + }, + + showMapPrintContainer() { + this.hideAllContainers(); + Element.mapPrintContainer.style.display = Constant.BLOCK; + + MapPrintManager.isVisited ? MapPrintView.render() : MapPrintManager.init(); + }, + + clearInput(element) { + element.value = ""; + }, +}; diff --git a/src/view/line-view.js b/src/view/line-view.js new file mode 100644 index 000000000..abae4870c --- /dev/null +++ b/src/view/line-view.js @@ -0,0 +1,43 @@ +import { Line } from "../model/line.js"; +import { Station } from "../model/station.js"; +import { Constant } from "../util/constant.js"; +import { Element } from "./element.js"; + +export const LineView = { + render() { + this.renderLineStartEndSelector(); + this.renderLineContainerTable(); + }, + + renderLineStartEndSelector() { + let content = ""; + + Station.stations.forEach((station) => { + content += ` + + `; + }); + + Element.lineStartStationSelector.innerHTML = content; + Element.lineEndStationSelector.innerHTML = content; + }, + + renderLineContainerTable() { + let content = ""; + + Line.lines.forEach(({ name, stations }) => { + content += ` + + ${name} + ${stations[0]} + ${stations[stations.length - 1]} + + + + + `; + }); + + Element.lineContainer.querySelector(Constant.TBODY).innerHTML = content; + }, +}; diff --git a/src/view/map-print-view.js b/src/view/map-print-view.js new file mode 100644 index 000000000..3a047c2b8 --- /dev/null +++ b/src/view/map-print-view.js @@ -0,0 +1,20 @@ +import { Line } from "../model/line.js"; +import { Element } from "./element.js"; + +export const MapPrintView = { + render() { + let content = '
'; + + Line.lines.forEach(({ name, stations }) => { + content += `

${name}

"; + }); + content += "
"; + + Element.mapPrintContainer.innerHTML = content; + }, +}; diff --git a/src/view/section-view.js b/src/view/section-view.js new file mode 100644 index 000000000..4a2763e51 --- /dev/null +++ b/src/view/section-view.js @@ -0,0 +1,74 @@ +import { Line } from "../model/line.js"; +import { Station } from "../model/station.js"; +import { Constant } from "../util/constant.js"; +import { Element, ElementControl } from "./element.js"; + +export const SectionView = { + render() { + this.renderSectionLineMenuButton(); + + ElementControl.hideSectionManager(); + }, + + renderSectionLineMenuButton() { + let content = ""; + + Line.lines.forEach(({ name }) => { + content += ` + + `; + }); + + Element.sectionLineMenu.innerHTML = content; + }, + + renderSectionManager(line) { + this.renderSectionManagerTitle(line); + this.renderSectionStationSelector(); + this.renderSectionContainerTable(line); + + ElementControl.showSectionManager(); + }, + + renderSectionManagerTitle(line) { + const sectionManagerTitleContent = `${line} ๊ด€๋ฆฌ`; + + Element.sectionManagerTitle.innerHTML = sectionManagerTitleContent; + }, + + renderSectionStationSelector() { + let content = ""; + + Station.stations.forEach((station) => { + content += ` + + `; + }); + + Element.sectionStationSelector.innerHTML = content; + }, + + renderSectionContainerTable(line) { + const stationArray = Line.lines.filter(({ name }) => name === line)[0] + .stations; + let content = ""; + + for (let i = 0; i < stationArray.length; i++) { + content += ` + + ${i} + ${stationArray[i]} + + + + + `; + } + + Element.sectionContainer.querySelector(Constant.TBODY).innerHTML = content; + }, +}; diff --git a/src/view/station-view.js b/src/view/station-view.js new file mode 100644 index 000000000..0a97d72e1 --- /dev/null +++ b/src/view/station-view.js @@ -0,0 +1,22 @@ +import { Station } from "../model/station.js"; +import { Constant } from "../util/constant.js"; +import { Element } from "./element.js"; + +export const StationView = { + render() { + let content = ""; + + Station.stations.forEach((station) => { + content += ` + + ${station} + + + + + `; + }); + + Element.stationContainer.querySelector(Constant.TBODY).innerHTML = content; + }, +}; diff --git a/style.css b/style.css new file mode 100644 index 000000000..5a7579515 --- /dev/null +++ b/style.css @@ -0,0 +1,46 @@ +/* table */ +table { + border: 1px solid gray; +} + +th, +td { + border: 1px solid gray; +} + +/* ์—ญ ๊ด€๋ฆฌ */ +.station-container { + padding-top: 20px; + display: none; +} + +/* ๋…ธ์„  ๊ด€๋ฆฌ */ +.line-container { + padding-top: 20px; + display: none; +} + +#line-start-end-station { + padding-top: 20px; + padding-bottom: 20px; +} + +/* ๊ตฌ๊ฐ„ ๊ด€๋ฆฌ */ +.section-container { + padding-top: 20px; + display: none; +} + +.section-manager { + display: none; +} + +#section-container-table { + margin-top: 40px; +} + +/* ์ง€ํ•˜์ฒ  ๋…ธ์„ ๋„ ๊ด€๋ฆฌ */ +.map-print-container { + padding-top: 20px; + display: none; +}