initial thingies
This commit is contained in:
commit
c4ef800f82
8694
package-lock.json
generated
Normal file
8694
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
43
package.json
Normal file
43
package.json
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"name": "prayercircle",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"compile": "webpack --config webpack.config.js",
|
||||||
|
"start": "ts-node src/server/index.ts",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.11.6",
|
||||||
|
"@babel/plugin-transform-runtime": "^7.11.5",
|
||||||
|
"@babel/polyfill": "^7.11.5",
|
||||||
|
"autoprefixer": "^10.0.1",
|
||||||
|
"babel-loader": "^8.1.0",
|
||||||
|
"babel-preset-env": "^1.7.0",
|
||||||
|
"clean-webpack-plugin": "^3.0.0",
|
||||||
|
"copy-webpack-plugin": "^6.1.1",
|
||||||
|
"css-loader": "^4.3.0",
|
||||||
|
"extract-loader": "^5.1.0",
|
||||||
|
"file-loader": "^6.1.0",
|
||||||
|
"html-loader": "^1.3.1",
|
||||||
|
"html-webpack-plugin": "^4.5.0",
|
||||||
|
"mini-css-extract-plugin": "^0.11.2",
|
||||||
|
"node-sass": "^5.0.0",
|
||||||
|
"postcss-loader": "^4.0.4",
|
||||||
|
"sass-loader": "^10.1.0",
|
||||||
|
"terser-webpack-plugin": "^4.2.2",
|
||||||
|
"ts-loader": "^8.0.4",
|
||||||
|
"typescript": "^4.0.2",
|
||||||
|
"webpack": "^4.44.2",
|
||||||
|
"webpack-cli": "^3.3.12",
|
||||||
|
"dotenv": "^8.2.0",
|
||||||
|
"ts-node": "^9.1.1",
|
||||||
|
"js-helper": "git+https://github.com/Ainias/js-helper.git#0.6.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.17.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
src/client/img/doge.png
Normal file
BIN
src/client/img/doge.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 204 KiB |
196
src/client/img/trashcan.svg
Normal file
196
src/client/img/trashcan.svg
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||||
|
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||||
|
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg"
|
||||||
|
width="1.70667in" height="1.70667in"
|
||||||
|
viewBox="0 0 512 512">
|
||||||
|
<path id="Auswahl"
|
||||||
|
stroke="black" stroke-width="1"
|
||||||
|
d="M 3.00,32.00
|
||||||
|
C 11.60,32.19 14.07,27.79 22.00,24.60
|
||||||
|
22.00,24.60 38.00,19.25 38.00,19.25
|
||||||
|
38.00,19.25 49.00,16.91 49.00,16.91
|
||||||
|
49.00,16.91 57.00,14.46 57.00,14.46
|
||||||
|
57.00,14.46 73.00,11.96 73.00,11.96
|
||||||
|
73.00,11.96 85.00,9.42 85.00,9.42
|
||||||
|
85.00,9.42 109.00,6.88 109.00,6.88
|
||||||
|
109.00,6.88 117.00,5.12 117.00,5.12
|
||||||
|
117.00,5.12 160.00,2.00 160.00,2.00
|
||||||
|
160.00,2.00 180.00,0.00 180.00,0.00
|
||||||
|
180.00,0.00 336.00,0.00 336.00,0.00
|
||||||
|
343.97,0.12 340.87,1.94 350.00,2.00
|
||||||
|
350.00,2.00 354.00,2.00 354.00,2.00
|
||||||
|
354.00,2.00 397.83,5.24 397.83,5.24
|
||||||
|
397.83,5.24 404.04,6.87 404.04,6.87
|
||||||
|
404.04,6.87 432.00,10.04 432.00,10.04
|
||||||
|
432.00,10.04 439.00,11.78 439.00,11.78
|
||||||
|
439.00,11.78 457.91,14.95 457.91,14.95
|
||||||
|
457.91,14.95 465.04,17.16 465.04,17.16
|
||||||
|
465.04,17.16 489.91,24.45 489.91,24.45
|
||||||
|
496.64,26.85 501.95,32.54 509.00,34.00
|
||||||
|
509.00,34.00 504.17,82.00 504.17,82.00
|
||||||
|
504.17,82.00 496.17,159.00 496.17,159.00
|
||||||
|
496.17,159.00 472.83,386.00 472.83,386.00
|
||||||
|
472.83,386.00 464.83,463.00 464.83,463.00
|
||||||
|
464.83,463.00 462.00,489.00 462.00,489.00
|
||||||
|
462.00,489.00 439.00,496.69 439.00,496.69
|
||||||
|
412.57,501.93 370.65,507.69 344.00,508.00
|
||||||
|
344.00,508.00 329.00,509.00 329.00,509.00
|
||||||
|
329.00,509.00 290.00,510.00 290.00,510.00
|
||||||
|
290.00,510.00 273.00,511.00 273.00,511.00
|
||||||
|
273.00,511.00 210.00,511.00 210.00,511.00
|
||||||
|
210.00,511.00 193.00,510.00 193.00,510.00
|
||||||
|
193.00,510.00 172.00,510.00 172.00,510.00
|
||||||
|
172.00,510.00 136.00,508.00 136.00,508.00
|
||||||
|
136.00,508.00 110.00,505.00 110.00,505.00
|
||||||
|
110.00,505.00 101.00,505.00 101.00,505.00
|
||||||
|
101.00,505.00 69.00,499.29 69.00,499.29
|
||||||
|
63.23,497.71 52.49,496.02 48.57,491.32
|
||||||
|
46.64,489.00 46.97,484.98 46.58,482.00
|
||||||
|
46.58,482.00 43.98,456.00 43.98,456.00
|
||||||
|
43.98,456.00 40.17,418.00 40.17,418.00
|
||||||
|
40.17,418.00 35.83,372.00 35.83,372.00
|
||||||
|
35.83,372.00 13.83,148.00 13.83,148.00
|
||||||
|
13.83,148.00 6.83,77.00 6.83,77.00
|
||||||
|
6.83,77.00 3.00,32.00 3.00,32.00 Z
|
||||||
|
M 113.00,78.00
|
||||||
|
C 113.00,78.00 81.00,74.38 81.00,74.38
|
||||||
|
81.00,74.38 72.00,72.12 72.00,72.12
|
||||||
|
72.00,72.12 50.00,68.30 50.00,68.30
|
||||||
|
50.00,68.30 29.00,62.19 29.00,62.19
|
||||||
|
29.00,62.19 18.00,58.00 18.00,58.00
|
||||||
|
18.00,58.00 19.83,76.00 19.83,76.00
|
||||||
|
19.83,76.00 24.83,130.00 24.83,130.00
|
||||||
|
24.83,130.00 40.83,302.00 40.83,302.00
|
||||||
|
40.83,302.00 51.83,421.00 51.83,421.00
|
||||||
|
51.83,421.00 57.00,475.00 57.00,475.00
|
||||||
|
57.00,475.00 66.00,478.69 66.00,478.69
|
||||||
|
66.00,478.69 73.00,479.46 73.00,479.46
|
||||||
|
73.00,479.46 82.00,481.54 82.00,481.54
|
||||||
|
82.00,481.54 95.00,483.43 95.00,483.43
|
||||||
|
101.43,484.52 103.05,485.91 110.00,486.00
|
||||||
|
123.92,486.17 117.37,487.13 124.09,488.71
|
||||||
|
124.09,488.71 136.00,490.00 136.00,490.00
|
||||||
|
136.00,490.00 135.00,474.00 135.00,474.00
|
||||||
|
135.00,474.00 134.00,451.00 134.00,451.00
|
||||||
|
134.00,451.00 133.00,437.00 133.00,437.00
|
||||||
|
133.00,437.00 131.00,396.00 131.00,396.00
|
||||||
|
131.00,396.00 130.00,382.00 130.00,382.00
|
||||||
|
130.00,382.00 128.00,342.00 128.00,342.00
|
||||||
|
128.00,342.00 127.04,332.00 127.04,332.00
|
||||||
|
127.04,332.00 127.04,324.00 127.04,324.00
|
||||||
|
127.04,324.00 126.00,305.00 126.00,305.00
|
||||||
|
126.00,305.00 125.04,295.00 125.04,295.00
|
||||||
|
125.04,295.00 125.04,287.00 125.04,287.00
|
||||||
|
125.04,287.00 124.00,269.00 124.00,269.00
|
||||||
|
124.00,269.00 123.00,255.00 123.00,255.00
|
||||||
|
123.00,255.00 122.00,233.00 122.00,233.00
|
||||||
|
122.00,233.00 121.00,218.00 121.00,218.00
|
||||||
|
121.00,218.00 120.00,201.00 120.00,201.00
|
||||||
|
120.00,201.00 119.00,179.00 119.00,179.00
|
||||||
|
119.00,179.00 118.00,164.00 118.00,164.00
|
||||||
|
118.00,164.00 116.00,123.00 116.00,123.00
|
||||||
|
116.00,123.00 115.00,110.00 115.00,110.00
|
||||||
|
115.00,110.00 113.00,78.00 113.00,78.00 Z
|
||||||
|
M 493.00,58.00
|
||||||
|
C 493.00,58.00 481.00,61.80 481.00,61.80
|
||||||
|
481.00,61.80 473.00,64.83 473.00,64.83
|
||||||
|
473.00,64.83 459.00,67.84 459.00,67.84
|
||||||
|
459.00,67.84 450.00,70.54 450.00,70.54
|
||||||
|
450.00,70.54 432.00,73.27 432.00,73.27
|
||||||
|
432.00,73.27 413.00,76.72 413.00,76.72
|
||||||
|
413.00,76.72 404.74,78.74 404.74,78.74
|
||||||
|
404.74,78.74 403.00,88.00 403.00,88.00
|
||||||
|
403.00,88.00 402.00,99.00 402.00,99.00
|
||||||
|
402.00,99.00 402.00,108.00 402.00,108.00
|
||||||
|
402.00,108.00 396.91,187.00 396.91,187.00
|
||||||
|
396.91,187.00 390.91,281.00 390.91,281.00
|
||||||
|
390.91,281.00 389.09,294.00 389.09,294.00
|
||||||
|
389.09,294.00 384.00,372.00 384.00,372.00
|
||||||
|
384.00,372.00 384.00,381.00 384.00,381.00
|
||||||
|
384.00,381.00 380.09,436.00 380.09,436.00
|
||||||
|
380.09,436.00 376.00,487.00 376.00,487.00
|
||||||
|
376.00,487.00 385.00,486.00 385.00,486.00
|
||||||
|
385.00,486.00 381.00,484.00 381.00,484.00
|
||||||
|
391.63,484.48 402.51,484.61 413.00,482.34
|
||||||
|
413.00,482.34 426.00,479.01 426.00,479.01
|
||||||
|
437.40,476.56 438.80,477.78 451.00,473.00
|
||||||
|
451.00,473.00 457.83,405.00 457.83,405.00
|
||||||
|
457.83,405.00 465.17,328.00 465.17,328.00
|
||||||
|
465.17,328.00 468.83,301.00 468.83,301.00
|
||||||
|
468.83,301.00 480.17,184.00 480.17,184.00
|
||||||
|
480.17,184.00 487.18,114.00 487.18,114.00
|
||||||
|
487.18,114.00 488.82,106.00 488.82,106.00
|
||||||
|
488.82,106.00 493.00,58.00 493.00,58.00 Z
|
||||||
|
M 382.00,80.00
|
||||||
|
C 382.00,80.00 345.00,83.00 345.00,83.00
|
||||||
|
345.00,83.00 332.00,84.04 332.00,84.04
|
||||||
|
332.00,84.04 317.00,84.04 317.00,84.04
|
||||||
|
317.00,84.04 305.00,85.00 305.00,85.00
|
||||||
|
305.00,85.00 268.00,85.00 268.00,85.00
|
||||||
|
268.00,85.00 268.00,111.00 268.00,111.00
|
||||||
|
268.00,111.00 267.00,128.00 267.00,128.00
|
||||||
|
267.00,128.00 267.00,243.00 267.00,243.00
|
||||||
|
267.00,243.00 266.00,258.00 266.00,258.00
|
||||||
|
266.00,258.00 266.00,372.00 266.00,372.00
|
||||||
|
266.00,372.00 265.00,387.00 265.00,387.00
|
||||||
|
265.00,387.00 265.00,493.00 265.00,493.00
|
||||||
|
265.00,493.00 304.00,492.00 304.00,492.00
|
||||||
|
304.00,492.00 321.00,491.00 321.00,491.00
|
||||||
|
321.00,491.00 342.00,490.09 342.00,490.09
|
||||||
|
342.00,490.09 359.00,489.00 359.00,489.00
|
||||||
|
359.00,489.00 361.00,448.00 361.00,448.00
|
||||||
|
361.00,448.00 362.00,433.00 362.00,433.00
|
||||||
|
362.00,433.00 363.00,415.00 363.00,415.00
|
||||||
|
363.00,415.00 364.00,396.00 364.00,396.00
|
||||||
|
364.00,396.00 365.00,375.00 365.00,375.00
|
||||||
|
365.00,375.00 366.00,359.00 366.00,359.00
|
||||||
|
366.00,359.00 367.00,335.00 367.00,335.00
|
||||||
|
367.00,335.00 368.08,322.00 368.08,322.00
|
||||||
|
368.08,322.00 368.08,313.00 368.08,313.00
|
||||||
|
368.08,313.00 370.00,301.00 370.00,301.00
|
||||||
|
370.00,301.00 370.00,292.00 370.00,292.00
|
||||||
|
370.00,292.00 371.00,278.00 371.00,278.00
|
||||||
|
371.00,278.00 372.00,258.00 372.00,258.00
|
||||||
|
372.00,258.00 373.00,244.00 373.00,244.00
|
||||||
|
373.00,244.00 375.00,202.00 375.00,202.00
|
||||||
|
375.00,202.00 375.96,192.00 375.96,192.00
|
||||||
|
375.96,192.00 375.96,184.00 375.96,184.00
|
||||||
|
375.96,184.00 377.00,165.00 377.00,165.00
|
||||||
|
377.00,165.00 378.00,147.00 378.00,147.00
|
||||||
|
378.00,147.00 379.00,131.00 379.00,131.00
|
||||||
|
379.00,131.00 380.00,115.00 380.00,115.00
|
||||||
|
380.00,115.00 381.00,93.00 381.00,93.00
|
||||||
|
381.00,93.00 382.00,80.00 382.00,80.00 Z
|
||||||
|
M 247.00,85.00
|
||||||
|
C 247.00,85.00 208.00,85.00 208.00,85.00
|
||||||
|
208.00,85.00 196.00,84.04 196.00,84.04
|
||||||
|
196.00,84.04 183.00,84.04 183.00,84.04
|
||||||
|
183.00,84.04 167.00,83.00 167.00,83.00
|
||||||
|
167.00,83.00 134.00,81.00 134.00,81.00
|
||||||
|
134.00,81.00 135.00,93.00 135.00,93.00
|
||||||
|
135.00,93.00 136.00,121.00 136.00,121.00
|
||||||
|
136.00,121.00 137.00,138.00 137.00,138.00
|
||||||
|
137.00,138.00 138.00,165.00 138.00,165.00
|
||||||
|
138.00,165.00 139.04,179.00 139.04,179.00
|
||||||
|
139.04,179.00 139.04,190.00 139.04,190.00
|
||||||
|
139.04,190.00 140.00,202.00 140.00,202.00
|
||||||
|
140.00,202.00 141.00,223.00 141.00,223.00
|
||||||
|
141.00,223.00 142.00,252.00 142.00,252.00
|
||||||
|
142.00,252.00 143.00,267.00 143.00,267.00
|
||||||
|
143.00,267.00 144.00,287.00 144.00,287.00
|
||||||
|
144.00,287.00 145.00,316.00 145.00,316.00
|
||||||
|
145.00,316.00 146.00,331.00 146.00,331.00
|
||||||
|
146.00,331.00 148.00,380.00 148.00,380.00
|
||||||
|
148.00,380.00 149.00,394.00 149.00,394.00
|
||||||
|
149.00,394.00 150.00,422.00 150.00,422.00
|
||||||
|
150.00,422.00 151.00,439.00 151.00,439.00
|
||||||
|
151.00,439.00 152.00,459.00 152.00,459.00
|
||||||
|
152.00,459.00 153.00,491.00 153.00,491.00
|
||||||
|
153.00,491.00 173.00,492.00 173.00,492.00
|
||||||
|
173.00,492.00 195.00,492.00 195.00,492.00
|
||||||
|
195.00,492.00 211.00,493.00 211.00,493.00
|
||||||
|
211.00,493.00 247.00,493.00 247.00,493.00
|
||||||
|
247.00,493.00 247.00,85.00 247.00,85.00 Z" />
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.9 KiB |
74
src/client/index.html
Normal file
74
src/client/index.html
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge"/>
|
||||||
|
<title>Prayercircle</title>
|
||||||
|
</head>
|
||||||
|
<body class="starting-page">
|
||||||
|
<div class="container">
|
||||||
|
<header class="header">
|
||||||
|
<div class="logo-container">
|
||||||
|
<!-- <img src="img/doge.png" alt="doge logo" class="logo-img"/>-->
|
||||||
|
<h1 class="logo-text">
|
||||||
|
<span class="logo-highlight">Prayer</span>Circle
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<section id="list-section">
|
||||||
|
<button id="add-button">+</button>
|
||||||
|
<div id="list-container">
|
||||||
|
<div id="input-template"><input class="name" placeholder="Name">
|
||||||
|
<button class="delete-button"></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
<section id="table-section">
|
||||||
|
<div id = "week-selection">
|
||||||
|
<button id = "previous-week"><</button>
|
||||||
|
<span id = "week-input"></span>
|
||||||
|
<button id = "next-week">></button>
|
||||||
|
</div>
|
||||||
|
<div id="table-container">
|
||||||
|
<table id="table-template" class="prayer-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="name"></th>
|
||||||
|
<th>Mo</th>
|
||||||
|
<th>Di</th>
|
||||||
|
<th>Mi</th>
|
||||||
|
<th>Do</th>
|
||||||
|
<th>Fr</th>
|
||||||
|
<th>Sa</th>
|
||||||
|
<th>So</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Ich bete für:</td>
|
||||||
|
<td class="for-0"></td>
|
||||||
|
<td class="for-1"></td>
|
||||||
|
<td class="for-2"></td>
|
||||||
|
<td class="for-3"></td>
|
||||||
|
<td class="for-4"></td>
|
||||||
|
<td class="for-5"></td>
|
||||||
|
<td class="for-6"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Für mich betet:</td>
|
||||||
|
<td class="by-0"></td>
|
||||||
|
<td class="by-1"></td>
|
||||||
|
<td class="by-2"></td>
|
||||||
|
<td class="by-3"></td>
|
||||||
|
<td class="by-4"></td>
|
||||||
|
<td class="by-5"></td>
|
||||||
|
<td class="by-6"></td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
138
src/client/js/CircleManager.js
Normal file
138
src/client/js/CircleManager.js
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
import {ViewHelper} from "js-helper/dist/client/ViewHelper";
|
||||||
|
import {Helper} from "js-helper/dist/shared/Helper";
|
||||||
|
|
||||||
|
export class CircleManager {
|
||||||
|
|
||||||
|
constructor(listSection, tableSection) {
|
||||||
|
this._members = [];
|
||||||
|
this._week = 0;
|
||||||
|
|
||||||
|
this._inputTemplate = listSection.querySelector("#input-template");
|
||||||
|
this._inputTemplate.remove();
|
||||||
|
this._inputTemplate.removeAttribute("id");
|
||||||
|
this._listContainer = listSection.querySelector("#list-container");
|
||||||
|
listSection.querySelector("#add-button").addEventListener("click", () => this.addMember());
|
||||||
|
|
||||||
|
this._tableTemplate = tableSection.querySelector("#table-template");
|
||||||
|
this._tableTemplate.remove();
|
||||||
|
this._tableTemplate.removeAttribute("id");
|
||||||
|
this._tableContainer = tableSection.querySelector("#table-container");
|
||||||
|
|
||||||
|
this._weekInput = tableSection.querySelector("#week-input");
|
||||||
|
tableSection.querySelector("#next-week").addEventListener("click", () => this.setWeek(this._week + 1));
|
||||||
|
tableSection.querySelector("#previous-week").addEventListener("click", () => this.setWeek(this._week - 1));
|
||||||
|
|
||||||
|
this.load();
|
||||||
|
this.setWeek(this._week);
|
||||||
|
}
|
||||||
|
|
||||||
|
setWeek(newWeek) {
|
||||||
|
newWeek = parseInt(newWeek);
|
||||||
|
if (!isNaN(newWeek)) {
|
||||||
|
newWeek = Math.max(newWeek, 0);
|
||||||
|
this._week = newWeek;
|
||||||
|
this._weekInput.innerText = (this._week + 1);
|
||||||
|
this.updateTables();
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
save(){
|
||||||
|
console.log("saving...");
|
||||||
|
localStorage.setItem("list", JSON.stringify({"week": this._week, "members": this._members}));
|
||||||
|
}
|
||||||
|
|
||||||
|
load(){
|
||||||
|
const jsonSavedata = localStorage.getItem("list");
|
||||||
|
console.log("liste", jsonSavedata);
|
||||||
|
if (jsonSavedata){
|
||||||
|
const data = JSON.parse(jsonSavedata);
|
||||||
|
this._week = data.week;
|
||||||
|
this._members = data.members;
|
||||||
|
this.updateList();
|
||||||
|
this.updateTables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateList() {
|
||||||
|
ViewHelper.removeAllChildren(this._listContainer);
|
||||||
|
this._members.forEach((member, id) => {
|
||||||
|
const memberElement = this._inputTemplate.cloneNode(true);
|
||||||
|
memberElement.querySelector(".delete-button").addEventListener("click", () => this.deleteMember(id))
|
||||||
|
|
||||||
|
const inputElem =
|
||||||
|
memberElement.querySelector(".name");
|
||||||
|
inputElem.value = member;
|
||||||
|
inputElem.addEventListener("input", () => {
|
||||||
|
this._members[id] = inputElem.value;
|
||||||
|
this.updateTables();
|
||||||
|
this.save();
|
||||||
|
});
|
||||||
|
this._listContainer.appendChild(memberElement);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteMember(index) {
|
||||||
|
if (index >= 0 && index < this._members.length) {
|
||||||
|
this._members.splice(index, 1);
|
||||||
|
this.updateList();
|
||||||
|
this.updateTables();
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addMember(name) {
|
||||||
|
name = Helper.nonNull(name, "");
|
||||||
|
this._members.push(name);
|
||||||
|
this.updateList();
|
||||||
|
this.updateTables();
|
||||||
|
this.save();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTables() {
|
||||||
|
if (this._members.length < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tables = {};
|
||||||
|
this._members.forEach((member, index) => {
|
||||||
|
const listPrayers = [];
|
||||||
|
const listPrayedBy = [];
|
||||||
|
|
||||||
|
const otherMembers = this._members.filter((v, i) => i !== index);
|
||||||
|
|
||||||
|
let prayersIndex = index - 1;
|
||||||
|
let prayedIndex = index;
|
||||||
|
|
||||||
|
const weekOffset = this._week * 7;
|
||||||
|
prayersIndex += weekOffset;
|
||||||
|
prayedIndex -= weekOffset;
|
||||||
|
if (prayedIndex < 0) {
|
||||||
|
prayedIndex += otherMembers.length * Math.floor(weekOffset / otherMembers.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < 7; i++) {
|
||||||
|
prayersIndex = (prayersIndex + 1) % otherMembers.length
|
||||||
|
prayedIndex = (prayedIndex - 1 + otherMembers.length) % otherMembers.length;
|
||||||
|
|
||||||
|
listPrayers.push(otherMembers[prayersIndex]);
|
||||||
|
listPrayedBy.push(otherMembers[prayedIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
tables[index] = {"for": listPrayers, "by": listPrayedBy}
|
||||||
|
});
|
||||||
|
|
||||||
|
ViewHelper.removeAllChildren(this._tableContainer);
|
||||||
|
Object.keys(tables).forEach(memberIndex => {
|
||||||
|
const tableElement = this._tableTemplate.cloneNode(true);
|
||||||
|
tableElement.querySelector(".name").innerText = this._members[memberIndex];
|
||||||
|
tables[memberIndex].for.forEach((otherMember, index) => {
|
||||||
|
tableElement.querySelector(".for-" + index).innerText = otherMember;
|
||||||
|
});
|
||||||
|
tables[memberIndex].by.forEach((otherMember, index) => {
|
||||||
|
tableElement.querySelector(".by-" + index).innerText = otherMember;
|
||||||
|
});
|
||||||
|
|
||||||
|
this._tableContainer.appendChild(tableElement);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/client/js/index.js
Normal file
7
src/client/js/index.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import "../sass/index.scss"
|
||||||
|
import {CircleManager} from "./CircleManager";
|
||||||
|
|
||||||
|
const listSegment = document.getElementById("list-section");
|
||||||
|
const tableSegment = document.getElementById("table-section");
|
||||||
|
|
||||||
|
new CircleManager(listSegment, tableSegment);
|
||||||
119
src/client/sass/index.scss
Normal file
119
src/client/sass/index.scss
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
font-family: "Montserrat", sans-serif;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
background-color: #f9fafc;
|
||||||
|
color: #595354;
|
||||||
|
}
|
||||||
|
|
||||||
|
#video-section {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.site-control {
|
||||||
|
font-size: 3rem;
|
||||||
|
padding: 0.2rem;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(0%, -50%);
|
||||||
|
|
||||||
|
&.previous {
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.next {
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
background-color: #ffffff;
|
||||||
|
padding: 10px 40px;
|
||||||
|
box-shadow: 0px 3px 6px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header > .logo-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header > .logo-container > .logo-img {
|
||||||
|
width: 60px;
|
||||||
|
height: 60px;
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header > .logo-container > .logo-text {
|
||||||
|
font-size: 26px;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header > .logo-container > .logo-text > .logo-highlight {
|
||||||
|
color: #65a9e5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#list-section{
|
||||||
|
margin: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background: white;
|
||||||
|
padding: 0 0.3rem;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
border: solid 1px black;
|
||||||
|
|
||||||
|
&.delete-button {
|
||||||
|
background: url("../img/trashcan.svg");
|
||||||
|
background-size: contain;
|
||||||
|
width: 1.5rem;
|
||||||
|
height: 1.5rem;
|
||||||
|
border: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
outline: none;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
|
||||||
|
&:placeholder-shown, &:focus {
|
||||||
|
border-bottom: solid 1px black;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#week-input{
|
||||||
|
width: 3rem;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
#table-section {
|
||||||
|
margin-top: 2rem;
|
||||||
|
|
||||||
|
#week-selection{
|
||||||
|
margin-left: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
#table-container {
|
||||||
|
.prayer-table {
|
||||||
|
max-width: calc(100% - 2rem);
|
||||||
|
margin: 1rem;
|
||||||
|
border: solid 1px #adadad;
|
||||||
|
border-collapse: collapse;
|
||||||
|
|
||||||
|
td, th {
|
||||||
|
padding: 0.2rem;
|
||||||
|
width: 12.5%;
|
||||||
|
border: solid 1px #adadad;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/server/Server.ts
Normal file
40
src/server/Server.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import * as express from "express";
|
||||||
|
import {createServer, Server as HTTPServer} from "http";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
export class Server {
|
||||||
|
private httpServer: HTTPServer;
|
||||||
|
private app: express.Application;
|
||||||
|
|
||||||
|
private activeSockets: string[] = [];
|
||||||
|
|
||||||
|
private readonly DEFAULT_PORT = 5000;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
private initialize(): void {
|
||||||
|
this.app = express();
|
||||||
|
this.httpServer = createServer(this.app);
|
||||||
|
|
||||||
|
this.configureApp();
|
||||||
|
this.configureRoutes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private configureApp(): void {
|
||||||
|
this.app.use(express.static(path.join(__dirname, "../../dist")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private configureRoutes(): void {
|
||||||
|
this.app.get("/", (req, res) => {
|
||||||
|
res.sendFile("index.html");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public listen(callback: (port: number) => void): void {
|
||||||
|
this.httpServer.listen(this.DEFAULT_PORT, () => {
|
||||||
|
callback(this.DEFAULT_PORT);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
99
src/server/TailStream.ts
Normal file
99
src/server/TailStream.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import * as stream from "stream";
|
||||||
|
import * as fs from "fs";
|
||||||
|
|
||||||
|
export class TailStream extends stream.Readable {
|
||||||
|
private filepath: string;
|
||||||
|
private fd;
|
||||||
|
private bytesRead: number = 0;
|
||||||
|
private dataAvailable: boolean;
|
||||||
|
private watcher;
|
||||||
|
private renamed: boolean = false;
|
||||||
|
|
||||||
|
constructor(filepath: string, opts?) {
|
||||||
|
super(opts);
|
||||||
|
this.filepath = filepath;
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
this.initWatcher();
|
||||||
|
}
|
||||||
|
|
||||||
|
private init() {
|
||||||
|
fs.open(this.filepath, 'r', (err, fd) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
this.fd = fd;
|
||||||
|
this.dataAvailable = true;
|
||||||
|
this._read();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_read() {
|
||||||
|
if (!this.dataAvailable || typeof this.fd !== "number") {
|
||||||
|
return this.push('');
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = Buffer.alloc(16 * 1024);
|
||||||
|
fs.read(this.fd, buffer, 0, buffer.length, this.bytesRead, (err, bytesRead) => {
|
||||||
|
if (err) {
|
||||||
|
console.error(err);
|
||||||
|
this.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (bytesRead === 0) {
|
||||||
|
if (this.renamed) {
|
||||||
|
this.end();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.dataAvailable = false;
|
||||||
|
this.push('');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!this.destroyed) {
|
||||||
|
this.bytesRead += bytesRead;
|
||||||
|
this.push(buffer.slice(0, bytesRead));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private initWatcher() {
|
||||||
|
this.watcher = fs.watch(this.filepath, (event, filename) => {
|
||||||
|
if (event === "change" && !this.dataAvailable) {
|
||||||
|
this.dataAvailable = true;
|
||||||
|
this.read(0);
|
||||||
|
} else if (event === "rename") {
|
||||||
|
if (this.filepath.endsWith(".tmp") && false) {
|
||||||
|
this.dataAvailable = false;
|
||||||
|
this.filepath = this.filepath.substring(0, this.filepath.length - 4);
|
||||||
|
this.renamed = true;
|
||||||
|
this.watcher.close();
|
||||||
|
if (this.fd) {
|
||||||
|
fs.close(this.fd, () => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.init();
|
||||||
|
this.initWatcher();
|
||||||
|
} else {
|
||||||
|
this.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private end() {
|
||||||
|
this.dataAvailable = false;
|
||||||
|
if (this.fd) {
|
||||||
|
fs.close(this.fd, () => {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.push(null);
|
||||||
|
if (this.watcher) {
|
||||||
|
this.watcher.close();
|
||||||
|
}
|
||||||
|
this.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
8
src/server/index.ts
Normal file
8
src/server/index.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { Server } from "./Server";
|
||||||
|
|
||||||
|
// const server = new DashServer();
|
||||||
|
const server = new Server();
|
||||||
|
|
||||||
|
server.listen(port => {
|
||||||
|
console.log(`Server is listening on http://localhost:${port}`);
|
||||||
|
});
|
||||||
221
webpack.config.js
Executable file
221
webpack.config.js
Executable file
@ -0,0 +1,221 @@
|
|||||||
|
require("dotenv").config();
|
||||||
|
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
|
||||||
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
|
const TerserPlugin = require("terser-webpack-plugin");
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const path = require("path");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
// const WorkboxPlugin = require('workbox-webpack-plugin');
|
||||||
|
|
||||||
|
|
||||||
|
let mode = (process.env.MODE || "development");
|
||||||
|
// let mode = (process.env.MODE || "production");
|
||||||
|
// let mode = "production";
|
||||||
|
|
||||||
|
// function getIp() {
|
||||||
|
// let ip = null;
|
||||||
|
// Object.keys(ifaces).some(function (ifname) {
|
||||||
|
// return ifaces[ifname].some(function (iface) {
|
||||||
|
// if ('IPv4' !== iface.family || iface.internal !== false) {
|
||||||
|
// // skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
|
||||||
|
// return false;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// ip = iface.address;
|
||||||
|
// return true;
|
||||||
|
// });
|
||||||
|
// });
|
||||||
|
// return ip;
|
||||||
|
// }
|
||||||
|
|
||||||
|
let moduleExports = {
|
||||||
|
|
||||||
|
//Development oder production, wird oben durch Variable angegeben (damit später per IF überprüft)
|
||||||
|
mode: mode,
|
||||||
|
|
||||||
|
//Beinhaltet den JS-Startpunkt und SCSS-Startpunkt
|
||||||
|
entry: [__dirname + "/src/client/js/index.js"],
|
||||||
|
// devtool: 'inline-source-map',
|
||||||
|
|
||||||
|
//Gibt Ausgabename und Ort für JS-File an
|
||||||
|
output: {
|
||||||
|
path: path.resolve(__dirname, 'dist'),
|
||||||
|
filename: "bundle.js"
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
extensions: [".ts", ".js", ".mjs", ".json", "png"]
|
||||||
|
},
|
||||||
|
|
||||||
|
optimization: {
|
||||||
|
// minimize: false
|
||||||
|
minimizer: [
|
||||||
|
new TerserPlugin({
|
||||||
|
cache: true,
|
||||||
|
parallel: true,
|
||||||
|
sourceMap: true, // Must be set to true if using source-maps in production
|
||||||
|
terserOptions: {
|
||||||
|
mangle: {
|
||||||
|
reserved: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins: [
|
||||||
|
//Delete www before every Build (to only have nessesary files)
|
||||||
|
new CleanWebpackPlugin({cleanOnceBeforeBuildPatterns: ['**/*', '!**/.gitkeep']}),
|
||||||
|
|
||||||
|
// new WorkboxPlugin.GenerateSW({
|
||||||
|
// maximumFileSizeToCacheInBytes: 1024 * 1024 * 1024 * 5
|
||||||
|
// }),
|
||||||
|
|
||||||
|
//Erstellt (kopiert) die Index.html
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: '!!html-loader!src/client/index.html'
|
||||||
|
}),
|
||||||
|
new webpack.DefinePlugin({}),
|
||||||
|
new MiniCssExtractPlugin(),
|
||||||
|
],
|
||||||
|
|
||||||
|
module: {
|
||||||
|
|
||||||
|
//Regeln: Wenn Regex zutrifft => führe Loader (in UMGEKEHRTER) Reihenfolge aus
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
//Kopiert HTML-Dateien in www. Nur die Dateien, welche im JS angefragt werden
|
||||||
|
test: /html[\\\/].*\.html$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: '[name].[ext]',
|
||||||
|
outputPath: 'html'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'extract-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'html-loader',
|
||||||
|
options: {
|
||||||
|
//Sorgt dafür, dass Child-Views funktionieren
|
||||||
|
attrs: [
|
||||||
|
":data-view",
|
||||||
|
":src",
|
||||||
|
"link:href"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.tsx?$/,
|
||||||
|
use: ["ts-loader"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//Kopiert nur benutzte Bilder/Videos/Sound (benutzt durch JS (import), html oder css/sass)
|
||||||
|
test: /(img|video|sound)[\\\/]/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
name: (resourcePath, resourceQuery) => {
|
||||||
|
// console.log("path", resourcePath);
|
||||||
|
// console.log("query", resourceQuery);
|
||||||
|
return "[name].[ext]"
|
||||||
|
},
|
||||||
|
outputPath: 'img',
|
||||||
|
publicPath: (url, resourcePath, context) => {
|
||||||
|
// console.log("url: ", url);
|
||||||
|
// console.log("resourcePath: ", resourcePath);
|
||||||
|
// console.log("context: ", context);
|
||||||
|
|
||||||
|
return "/img/" + url;
|
||||||
|
},
|
||||||
|
// useRelativePath: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//Compiliert SASS zu CSS und speichert es in Datei
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: [
|
||||||
|
// {
|
||||||
|
// loader: 'file-loader',
|
||||||
|
// options: {
|
||||||
|
// name: '[name].css',
|
||||||
|
// outputPath: 'css',
|
||||||
|
// // publicPath: '/css'
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// loader: 'extract-loader'
|
||||||
|
// },
|
||||||
|
{
|
||||||
|
loader: MiniCssExtractPlugin.loader,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'css-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//Compiliert zu CSS
|
||||||
|
loader: 'sass-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//Auslagerung von zeitintensiven Sachen in production only, damit Debugging schneller geht
|
||||||
|
if (mode === "production" && false) {
|
||||||
|
|
||||||
|
//Polyfills hinzufügen
|
||||||
|
moduleExports["entry"].unshift("@babel/polyfill");
|
||||||
|
// moduleExports["devtool"] = "source-map";
|
||||||
|
|
||||||
|
//Transpilieren zu ES5
|
||||||
|
moduleExports["module"]["rules"].push({
|
||||||
|
test: /\.m?js$/,
|
||||||
|
exclude: /node_modules\/(?!(cordova-sites|js-helper|cs-event-manager|polygon-geometry))/,
|
||||||
|
use: {
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
presets: ['@babel/preset-env'],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
moduleExports["module"]["rules"][1]["use"].unshift({
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
presets: ['@babel/preset-env'],
|
||||||
|
inputSourceMap: "inline",
|
||||||
|
sourceMaps: true
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Hinzufügen von POSTCSS und Autoprefixer für alte css-Präfixe
|
||||||
|
moduleExports["module"]["rules"][3]["use"].splice(3, 0, {
|
||||||
|
//PostCSS ist nicht wichtig, autoprefixer schon. Fügt Präfixes hinzu (Bsp.: -webkit), wo diese benötigt werden
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
|
plugins: [require('autoprefixer')()]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// moduleExports["optimization"] = {
|
||||||
|
// minimize: false,
|
||||||
|
// // minimizer: [new UglifyJsPlugin({
|
||||||
|
// // include: /\.min\.js$/
|
||||||
|
// // })]
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = moduleExports;
|
||||||
|
|
||||||
Loading…
x
Reference in New Issue
Block a user