g6
This commit is contained in:
1 parent
565c1b9911
commit
28490ce8b3
36 files changed
+587
-179
No files matched your search
@@ -0,0 +1,297 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.5">
|
||||
<link rel="stylesheet" href="../lib/basic.css">
|
||||
<script src="../auth.js"></script>
|
||||
<script src="../lib/basic.js"></script>
|
||||
<script src="../other/skills.js"></script>
|
||||
<script src="../other/skilltree.js"></script>
|
||||
<title>Auswertung</title>
|
||||
</head>
|
||||
<body>
|
||||
<style>
|
||||
|
||||
button.navigation {
|
||||
font-size: 20px;
|
||||
padding: 15px 15px;
|
||||
background-color: var(--accent_color_bg);
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
min-width: min(calc(160px + 40px), 100%);
|
||||
white-space: nowrap;
|
||||
}
|
||||
button.navigation:hover {
|
||||
background: var(--accent_color_bg_o);
|
||||
}
|
||||
|
||||
/*.header_bar_1 > div:first-child > div {
|
||||
display: inline;
|
||||
padding: 10px;
|
||||
padding-right: 30px;
|
||||
}
|
||||
.header_bar_1 > div:first-child > div:hover {
|
||||
background: rgba(127, 127, 127, 0.4);
|
||||
border-radius: var(--border-radius);
|
||||
}*/
|
||||
|
||||
.content-table {
|
||||
height: calc(100% - 75px);
|
||||
max-height: calc(100% - 75px);
|
||||
min-height: calc(100% - 75px);
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
top: 75px;
|
||||
left: 0;
|
||||
}
|
||||
.content-table > tbody > tr:first-child > td:first-child {
|
||||
width: 35%;
|
||||
vertical-align: top;
|
||||
padding: 20px;
|
||||
padding-right: 10px;
|
||||
height: 100%;
|
||||
}
|
||||
.content-table > tbody > tr:first-child > td > div {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
border: 3px solid var(--accent_color_bg);
|
||||
border-radius: var(--border-radius);
|
||||
padding: 10px;
|
||||
box-shadow: var(--reversed_def_shadow);
|
||||
background: var(--accent_color_bg_o2);
|
||||
min-height: 150px;
|
||||
}
|
||||
.content-table > tbody > tr:first-child > td:last-child {
|
||||
width: 65%;
|
||||
height: 100px;
|
||||
vertical-align: top;
|
||||
padding: 20px;
|
||||
padding-left: 10px !important;
|
||||
}
|
||||
.content-table > tbody > tr:first-child > td:last-child > div {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
max-height: 100%;
|
||||
padding: 15px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
.content-table > tbody > tr:first-child > td:last-child > div button {
|
||||
padding: 5px;
|
||||
font-size: 16px;
|
||||
font-weight: normal;
|
||||
margin-top: 5px;
|
||||
background-color: var(--accent_color_bg_o);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
#umfrage_list {
|
||||
width: 100%;
|
||||
}
|
||||
#umfrage_list > div {
|
||||
padding: 10px;
|
||||
border: 2px solid var(--accent_color_bg);
|
||||
border-radius: var(--border-radius);
|
||||
width: 100%;
|
||||
min-height: 100px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="header_bar_1">
|
||||
<div>
|
||||
<div>
|
||||
<button onclick="location.href = './uebersicht.html?user=' + userData.name;" class="navigation">Meine Kurse</button>
|
||||
</div>
|
||||
</div>
|
||||
<div><b>Auswertungen</b></div>
|
||||
<div>
|
||||
<button class="profile"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header_bar_1_placeholder"></div>
|
||||
|
||||
<table class="content-table"><tr>
|
||||
<td><div>
|
||||
<div id="gesamt" class="selectable"></div>
|
||||
</div></td>
|
||||
<td><div>
|
||||
<div id="umfrage_list"></div>
|
||||
</div></td>
|
||||
</tr></table>
|
||||
|
||||
<script>
|
||||
|
||||
const couchDB = new CouchDB();
|
||||
setUserData(couchDB).then(init);
|
||||
|
||||
var gesamtAuswertung = [0,0,0, []];
|
||||
|
||||
async function loadStats() {
|
||||
const gdiv = getId("gesamt");
|
||||
const udiv = getId("umfrage_list");
|
||||
|
||||
udiv.innerHTML = "";
|
||||
gesamtAuswertung = [0,0,0, []];
|
||||
for (var i of userData.courses) {
|
||||
const course = await couchDB.get("course:" + i);
|
||||
if (course == null) continue;
|
||||
|
||||
const list = course["result_history"] ?? [];
|
||||
for (var pos in list) {
|
||||
const i2 = list[pos];
|
||||
udiv.innerHTML += _createElement1(course, i2, i, pos);
|
||||
}
|
||||
udiv.innerHTML += _createElement1(course, {
|
||||
"date": course.expire_date,
|
||||
"questions": course.questions ?? [],
|
||||
"result": course.result ?? []
|
||||
}, i);
|
||||
}
|
||||
|
||||
const bottomLabel = document.createElement("label");
|
||||
bottomLabel.style = `display: inline-block; font-size: 5px;`;
|
||||
bottomLabel.innerHTML = " ";
|
||||
udiv.appendChild(bottomLabel);
|
||||
|
||||
let studenten = gesamtAuswertung[3].length == 0 ? 0 : gesamtAuswertung[3].reduce((acc, val) => acc + val, 0) / gesamtAuswertung[3].length;
|
||||
|
||||
|
||||
gdiv.innerHTML = `
|
||||
<b>Gesamtbewertung:</b><br><br>
|
||||
Positiv bewertet: ${round(gesamtAuswertung[0])}<br>
|
||||
Neutral bewertet: ${round(gesamtAuswertung[1])}<br>
|
||||
Negativ bewertet: ${round(gesamtAuswertung[2])}<br><br>
|
||||
<i>Studenten im Durchschnitt:</i> ${round(studenten)}
|
||||
`;
|
||||
}
|
||||
|
||||
function _createElement1(course, data, name, pos = -1) {
|
||||
const startDate = data.date;
|
||||
const title = course.title;
|
||||
|
||||
var startD = "Unbekannt";
|
||||
if (startDate) {
|
||||
startD = new Date(startDate).toLocaleDateString('de-DE', {year: 'numeric', month: 'long', day: 'numeric'});
|
||||
}
|
||||
|
||||
var statCount = [0,0,0];
|
||||
for (var i in data.result) {
|
||||
const result = data.result[i];
|
||||
|
||||
for (var i2 in result) {
|
||||
const question = data.questions[i2];
|
||||
const answer = result[i2];
|
||||
|
||||
if (question.type == "text") {
|
||||
continue;
|
||||
} else if (question.type == "scala") {
|
||||
if (answer == 5 || answer == 4) {
|
||||
statCount[0] ++;
|
||||
} else if (answer == 3) {
|
||||
statCount[1] ++;
|
||||
} else if (answer == 1 || answer == 2) {
|
||||
statCount[2] ++;
|
||||
}
|
||||
} else if (question.type == "emoji") {
|
||||
if (answer == 3) {
|
||||
statCount[0] ++;
|
||||
} else if (answer == 2) {
|
||||
statCount[1] ++;
|
||||
} else if (answer == 1) {
|
||||
statCount[2] ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
gesamtAuswertung[3].push(result.length);
|
||||
}
|
||||
|
||||
var total = statCount.reduce((acc, val) => acc + val, 0);
|
||||
var percentages;
|
||||
if (total > 0) {
|
||||
percentages = statCount.map(value => (value / total) * 100);
|
||||
} else {
|
||||
percentages = [0, 0, 0];
|
||||
}
|
||||
|
||||
var endNote;
|
||||
var bttn;
|
||||
if (percentages[0] > percentages[1] && percentages[0] > percentages[2]) {
|
||||
endNote = "Überwiegend positiv";
|
||||
gesamtAuswertung[0] ++;
|
||||
bttn = `<button onclick='getXpPoints(this, 2, "${name}", ${pos})'>2 XP abholen</button>`;
|
||||
} else if (percentages[2] > percentages[0] && percentages[2] > percentages[1]) {
|
||||
endNote = "Überwiegend negativ";
|
||||
gesamtAuswertung[2] ++;
|
||||
bttn = '';
|
||||
} else {
|
||||
endNote = "Gemischt";
|
||||
gesamtAuswertung[1] ++;
|
||||
bttn = `<button onclick='getXpPoints(this, 1, "${name}", ${pos})'>1 XP abholen</button>`;
|
||||
}
|
||||
|
||||
if ((data["got_xp"] ??= false) || pos == -1) {
|
||||
bttn = '';
|
||||
}
|
||||
|
||||
return `<div>
|
||||
<table style="width: 100%; border-collapse:collapse; " class="selectable">
|
||||
<tr>
|
||||
<td style="vertical-align: top; width: 60%; border-bottom: 1px solid black;">
|
||||
Umfrage vom ${startD}
|
||||
</td>
|
||||
<td style="vertical-align: top; text-align: right; width: 40%; border-bottom: 1px solid black;">
|
||||
Kurs: ${title}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-left: 15px; display: inline-block; padding-top: 10px; vertical-align: top;">
|
||||
Positive: ${round(percentages[0])}%<br>
|
||||
Negative: ${round(percentages[2])}%<br>
|
||||
Neutral: ${round(percentages[1])}%<br>
|
||||
</td>
|
||||
<td style="padding-top: 10px; vertical-align: top;">
|
||||
<u>Endnote</u>: ${endNote}<br>
|
||||
${bttn}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
function round(n) {
|
||||
return Number(n.toFixed(2)).toString();
|
||||
}
|
||||
|
||||
async function init() {
|
||||
await loadStats();
|
||||
}
|
||||
|
||||
async function getXpPoints(elm, xp, name, pos) {
|
||||
elm.remove();
|
||||
const course = await couchDB.get("course:" + name);
|
||||
|
||||
const history = course.result_history ??= [];
|
||||
|
||||
const data = history[pos];
|
||||
if (data == null) {
|
||||
console.error(`data is null at course ${name} history=${pos}`);
|
||||
return;
|
||||
}
|
||||
|
||||
data["got_xp"] = true;
|
||||
|
||||
if (await levelUpXP(couchDB, userData, xp)) {
|
||||
playLevelSound();
|
||||
} else {
|
||||
playXPSound();
|
||||
}
|
||||
|
||||
await couchDB.set("course:" + name, course);
|
||||
}
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,347 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.5">
|
||||
<link rel="stylesheet" href="../lib/basic.css">
|
||||
<script src="../auth.js"></script>
|
||||
<script src="../lib/basic.js"></script>
|
||||
<script src="../other/skills.js"></script>
|
||||
<script src="../other/skilltree.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/qrcodejs/qrcode.min.js"></script>
|
||||
<script>
|
||||
const couchDB = new CouchDB();
|
||||
setUserData(couchDB);
|
||||
</script>
|
||||
<title>Kurs Anzeige</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header_bar_1">
|
||||
<button class="back" onclick="location.href = './uebersicht.html?user=' + userData.name;">
|
||||
Übersicht
|
||||
</button>
|
||||
<div>
|
||||
<!-- <button class="profile" onclick='showOverlay("miniProfile")' style="position: absolute; top: 7px; right: 15px;">
|
||||
<overlay class="my_overlay" id="miniProfile">
|
||||
</overlay>
|
||||
</button> -->
|
||||
<button class="profile" style="position: absolute; top: 7px; right: 15px;"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="contentLayout">
|
||||
<div class="qrColumn">
|
||||
<div id="qrCode"></div>
|
||||
<span id="accesCode"></span>
|
||||
</div>
|
||||
|
||||
<div class="questionColumn">
|
||||
<div id="questionCards"></div>
|
||||
</div>
|
||||
</div>
|
||||
<button class="live" id="liveButton" onclick="AnsichtZeigen()">
|
||||
Live Ansicht
|
||||
</button>
|
||||
</body>
|
||||
|
||||
|
||||
<script>
|
||||
const params = getURLArgsMap();
|
||||
const courseId = params["course"];
|
||||
|
||||
if (!courseId) {
|
||||
console.error("Keine courseId in der URL");
|
||||
}
|
||||
|
||||
const qrCodeUrl = `${window.location.origin}/student/umfrage.html?course=${courseId}`;
|
||||
|
||||
new QRCode(document.getElementById("qrCode"), {
|
||||
text: qrCodeUrl,
|
||||
width: 500,
|
||||
height: 500,
|
||||
})
|
||||
|
||||
const accesCodeElem = document.getElementById("accesCode");
|
||||
accesCodeElem.innerText = "Code: " + courseId;
|
||||
|
||||
async function AnsichtZeigen() {
|
||||
const liveButton = document.getElementById("liveButton")
|
||||
liveButton.style.display = "none";
|
||||
|
||||
const questionList = document.getElementById("questionCards");
|
||||
|
||||
const courseInfo = await couchDB.get("course:" + courseId);
|
||||
let index = 0;
|
||||
for(const question of courseInfo.questions) {
|
||||
const overlayId = `qOver${index}`
|
||||
const answerContainerId = `answerContainer${index}`;
|
||||
|
||||
|
||||
const card = document.createElement("div");
|
||||
card.className = "questionCard";
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="questionTitle">${question.title}</div>
|
||||
|
||||
<button class="questionResults" onclick='questionOverlay("${overlayId}", "${index}")'>
|
||||
Auswertung
|
||||
<overlay class="my_overlay" id="${overlayId}">
|
||||
<div class="overlayTitle">
|
||||
${question.title}:
|
||||
</div>
|
||||
<div id="${answerContainerId}"></div>
|
||||
</overlay>
|
||||
</button>
|
||||
`;
|
||||
questionList.appendChild(card);
|
||||
index++;
|
||||
}
|
||||
|
||||
}
|
||||
async function questionOverlay(overlayId, index) {
|
||||
|
||||
const awnserList = document.getElementById(`answerContainer${index}`)
|
||||
const courseInfo = await couchDB.get("course:" + courseId)
|
||||
awnserList.innerHTML = "";
|
||||
|
||||
switch(courseInfo.questions[index].type) {
|
||||
case "text":
|
||||
let j = 0;
|
||||
for(awnser of courseInfo.result) {
|
||||
const resultDisplay = document.createElement("div");
|
||||
resultDisplay.className = "overlayTextRes"
|
||||
resultDisplay.innerHTML = `<div>Antwort ${j + 1}: ${awnser[index]} </div>`
|
||||
awnserList.appendChild(resultDisplay)
|
||||
j++;
|
||||
}
|
||||
break;
|
||||
|
||||
case "scala":
|
||||
var score = 0;
|
||||
for (let j = 0; j < courseInfo.result.length; j++) {
|
||||
score += courseInfo.result[j][index];
|
||||
}
|
||||
var percent;
|
||||
if (courseInfo.result.length > 0) {
|
||||
score = score / courseInfo.result.length;
|
||||
percent = (score/5)*100;
|
||||
} else {
|
||||
score = 0;
|
||||
percent = 0;
|
||||
}
|
||||
|
||||
console.log(courseInfo.result.length);
|
||||
|
||||
const resultDisplay = document.createElement("div");
|
||||
resultDisplay.className = "overlayScalaRes"
|
||||
resultDisplay.innerHTML = `
|
||||
<div class="overlayTextRes"> ${percent}% positive </div>
|
||||
<div class="scoreBar">
|
||||
<div class="scoreFill" id="scoreFill${index}" style="width: ${(score/5)*100}%"></div>
|
||||
</div>`;
|
||||
|
||||
awnserList.appendChild(resultDisplay);
|
||||
|
||||
const scoreFill = document.getElementById(`scoreFill${index}`)
|
||||
if(percent < 30) {
|
||||
scoreFill.style.backgroundColor = "red";
|
||||
} else if(percent < 70) {
|
||||
scoreFill.style.backgroundColor = "orange";
|
||||
} else {
|
||||
scoreFill.style.backgroundColor = "green";
|
||||
}
|
||||
break;
|
||||
|
||||
case "emoji":
|
||||
let scoreE = 0;
|
||||
for(let j = 0; j < courseInfo.result.length; j++) {scoreE += courseInfo.result[j][index]};
|
||||
scoreE = scoreE / courseInfo.result.length;
|
||||
const percentE = (scoreE/5)*100;
|
||||
|
||||
const resultDisplayE = document.createElement("div");
|
||||
resultDisplayE.className = "overlayScalaRes"
|
||||
resultDisplayE.innerHTML = `
|
||||
<div class="overlayTextRes"> ${percentE}% positive </div>
|
||||
<div class="scoreBar">
|
||||
<div class="scoreFill" id="scoreFill${index}" style="width: ${(scoreE/5)*100}%"></div>
|
||||
</div>`;
|
||||
|
||||
|
||||
awnserList.appendChild(resultDisplayE);
|
||||
|
||||
const scoreFillE = document.getElementById(`scoreFill${index}`)
|
||||
if(percentE < 30) {
|
||||
scoreFillE.style.backgroundColor = "red";
|
||||
} else if(percentE < 70) {
|
||||
scoreFillE.style.backgroundColor = "orange";
|
||||
} else {
|
||||
scoreFillE.style.backgroundColor = "green";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
showOverlay(overlayId);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.scoreBar {
|
||||
width: 90vh;
|
||||
height: 30px;
|
||||
background-color: antiquewhite;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.scoreFill {
|
||||
height: 100%;
|
||||
width: 0%;
|
||||
background-color: #008000;
|
||||
transition: width 0.5s ease;
|
||||
}
|
||||
|
||||
.my_overlay {
|
||||
width: 100vh;
|
||||
min-height: 30vh;
|
||||
}
|
||||
|
||||
.overlayTitle {
|
||||
font-weight: bold;
|
||||
background: var(--accent_color_bg);
|
||||
/*border-radius: calc(var(--border-radius) + 20px);*/
|
||||
border-radius: var(--border-radius) var(--border-radius) 0 0;
|
||||
}
|
||||
|
||||
.overlayTitle {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
max-width: 90vh;
|
||||
}
|
||||
|
||||
.overlayTextRes {
|
||||
padding: 10px;
|
||||
font-display: flex;
|
||||
flex-direction: column;
|
||||
min-width: 0;
|
||||
background: var(--accent_color_bg_o);
|
||||
/*border-radius: calc(var(--border-radius) + 20px);*/
|
||||
max-width: 90vh;
|
||||
}
|
||||
#answerContainer0 .overlayTextRes:last-child {
|
||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||
}
|
||||
#answerContainer1 .overlayScalaRes:last-child > .overlayTextRes {
|
||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||
}
|
||||
|
||||
.contentLayout {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
gap: 80px;
|
||||
margin-top: 15vh;
|
||||
padding: 0 5vw;
|
||||
}
|
||||
|
||||
.questionCard {
|
||||
position: relative;
|
||||
width: 400px;
|
||||
min-height: 100px;
|
||||
padding: 16px;
|
||||
background: var(--accent_color_bg_o);
|
||||
border-radius: 12px;
|
||||
box-shadow: var(--def-shadow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.questionTitle {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.questionResults {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.questionColumn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 20px;
|
||||
max-width: 320;
|
||||
}
|
||||
|
||||
button.back {
|
||||
font-size: 20px;
|
||||
padding: 15px;
|
||||
padding-left: 40px;
|
||||
padding-right: 40px;
|
||||
background-color: var(--accent_color_bg);
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.back:focus-visible {
|
||||
outline: 2px var(--accent_color_fg_o);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
button.back:hover {
|
||||
background: var(--accent_color_bg_o);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.qrColumn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
margin-top: 1vh;
|
||||
}
|
||||
|
||||
#accesCode {
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--accent_color_bg_o);
|
||||
box-shadow: var(--def-shadow);
|
||||
}
|
||||
|
||||
#qrCode img,
|
||||
#qrCode canvas {
|
||||
padding: 14px;
|
||||
border: 4px solid var(--accent_color_fg_o);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--accent_color_bg_o);
|
||||
box-sizing: border-box;
|
||||
box-shadow: var(--def-shadow);
|
||||
}
|
||||
|
||||
button.live {
|
||||
position: absolute;
|
||||
padding: 15px;
|
||||
bottom: 8vh;
|
||||
right: 8vh;
|
||||
font-size: 40px;
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
background-color: var(--accent_color_bg);
|
||||
box-shadow: var(--def-shadow);
|
||||
}
|
||||
|
||||
button.live:hover {
|
||||
background: var(--accent_color_bg_o);
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,616 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.5">
|
||||
<link rel="stylesheet" href="../lib/basic.css">
|
||||
<script src="../auth.js"></script>
|
||||
<script src="../lib/basic.js"></script>
|
||||
<script src="../other/skills.js"></script>
|
||||
<script src="../other/skilltree.js"></script>
|
||||
<script>
|
||||
const couchDB = new CouchDB();
|
||||
setUserData(couchDB);
|
||||
</script>
|
||||
<title>Übersicht</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="header_bar_1">
|
||||
<div style="font-weight: bold;">
|
||||
Meine Kurse
|
||||
</div>
|
||||
<div>
|
||||
<button class="auswertung" onclick='location.href = "./auswertung.html?user=" + userData.name'>
|
||||
Auswertungen
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="profile" onclick='showOverlay("miniProfile")'>
|
||||
<overlay id="miniProfile">
|
||||
hello
|
||||
</overlay>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header_bar_1_placeholder"></div>
|
||||
|
||||
<content>
|
||||
<div id="course-list"></div>
|
||||
|
||||
<button class="new" id="newButton" onclick="showCourseCreation()">+</button>
|
||||
|
||||
<overlay id="createCourse" class="createCourse">
|
||||
<input placeholder="Kursname" style="width: calc(100% - 50px);"><br><br>
|
||||
Beschreibung:
|
||||
<textarea placeholder="Beschreibung"></textarea><br><br>
|
||||
Feedback-Fragen:
|
||||
<div class="evaluations">
|
||||
<div></div>
|
||||
<button class="add_button" onclick="createCourseNewEvaluation()">+</button>
|
||||
</div><br>
|
||||
Start-Termin: <input type="date" style="margin-bottom: 5px;"><br>
|
||||
Abgabe-Termin: <input type="date"><br><br>
|
||||
<button onclick="saveCreateCourse()">Kurs erstellen</button>
|
||||
</overlay>
|
||||
|
||||
<overlay id="deletionConfirmation">
|
||||
<p style="padding: 15px;"> Wollen sie wirklich diesen Kurs löschen?</p>
|
||||
<div style="display: flex; gap: 15px; justify-content: center;">
|
||||
<button class="confirmation" onclick="confirmNo()">Abbrechen</button>
|
||||
<button class="confirmation" onclick="confirmYes()">OK</button>
|
||||
</div>
|
||||
</overlay>
|
||||
</content>
|
||||
|
||||
<style>
|
||||
button.confirmation {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
padding: 10px;
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--accent_color_fg);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.confirmation:hover {
|
||||
background-color: var(--accent_color_fg_o);
|
||||
}
|
||||
|
||||
button.new {
|
||||
display: block;
|
||||
margin: 20px auto;
|
||||
font-size: 30px;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border-radius: 50%;
|
||||
background-color: var(--accent_color_bg);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.new:hover {
|
||||
background-color: var(--accent_color_bg_o);
|
||||
}
|
||||
|
||||
button.auswertung {
|
||||
font-size: 20px;
|
||||
padding: 15px;
|
||||
padding-left: 40px;
|
||||
padding-right: 40px;
|
||||
background-color: var(--accent_color_bg);
|
||||
border: none;
|
||||
border-radius: var(--border-radius);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.auswertung:focus-visible {
|
||||
outline: 2px var(--accent_color_fg_o);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
button.auswertung:hover {
|
||||
background: var(--accent_color_bg_o);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.course-card {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
min-height: 300px;
|
||||
padding: 16px;
|
||||
background: var(--accent_color_bg_o);
|
||||
border-radius: 12px;
|
||||
box-shadow: var(--def-shadow);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.course-title {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
font-size: 25px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.course-description {
|
||||
margin: 0;
|
||||
font-size: 20px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.course-actions {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
.action {
|
||||
padding: 8px;
|
||||
border: none;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.action.start {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 70px;
|
||||
font-size: 20px;
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--accent_color_bg);
|
||||
}
|
||||
|
||||
.action.start:hover {
|
||||
background: var(--accent_color_bg_o);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.action.delete {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
font-size: 20px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
max-height: 40px;
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--accent_color_bg);
|
||||
}
|
||||
|
||||
.action.delete:hover {
|
||||
background: var(--accent_color_bg_o);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.action.edit {
|
||||
position: absolute;
|
||||
bottom: 16px;
|
||||
right: 16px;
|
||||
font-size: 25px;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
border-radius: var(--border-radius);
|
||||
background-color: var(--accent_color_bg);
|
||||
}
|
||||
|
||||
.action.edit:hover {
|
||||
background: var(--accent_color_bg_o);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
#course-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.createCourse {
|
||||
min-width: 70% !important;
|
||||
}
|
||||
.createCourse input {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
padding: 4px;
|
||||
background: none;
|
||||
border: 1px solid black;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.createCourse textarea {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
resize: none;
|
||||
padding: 4px;
|
||||
background: none;
|
||||
border: 1px solid black;
|
||||
height: 100px;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.createCourse .evaluations {
|
||||
overflow-y: auto;
|
||||
text-align: center;
|
||||
max-height: 300px;
|
||||
border: 2px solid grey;
|
||||
padding: 10px;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.createCourse .evaluations .evaluation {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid black;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
}
|
||||
.createCourse .evaluation input {
|
||||
display: inline-block;
|
||||
font-size: 20px !important;
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
.createCourse .evaluation > select {
|
||||
width: 90%;
|
||||
font-size: 18px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.createCourse .evaluation > button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 23px;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.createCourse > button {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 4px;
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(async () => {
|
||||
await setUserData(couchDB);
|
||||
await setCourseView();
|
||||
})();
|
||||
|
||||
async function setCourseView() {
|
||||
const courseList = document.getElementById("course-list");
|
||||
courseList.innerHTML = "";
|
||||
|
||||
for(const courseId of userData.courses) {
|
||||
const course = await couchDB.get("course:" + courseId);
|
||||
|
||||
const card = document.createElement("div");
|
||||
card.className = "course-card";
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="course-title">${course.title}</div>
|
||||
|
||||
<div class="course-description">
|
||||
${course.description}
|
||||
</div>
|
||||
|
||||
<button class="action start" onclick='location.href = "./kursAnzeige.html?user=${userData.name},course=${courseId}";'>
|
||||
Umfrage Starten
|
||||
</button>
|
||||
|
||||
<button class="action edit" onclick="showEditCourse('${courseId}')">
|
||||
✎
|
||||
</button>
|
||||
|
||||
<button class="action delete" onclick="deleteCourse('${courseId}')">
|
||||
🗑
|
||||
</button>
|
||||
`;
|
||||
courseList.appendChild(card);
|
||||
}
|
||||
}
|
||||
|
||||
function createCourseNewEvaluation() {
|
||||
const elm = getOverlay("createCourse");
|
||||
if (elm == null) return;
|
||||
|
||||
const evaluations = elm.querySelector(".evaluations > div");
|
||||
evaluations.appendChild(createEvaluation({
|
||||
"title": "", "type": "text"
|
||||
}));
|
||||
}
|
||||
|
||||
async function saveCreateCourse() {
|
||||
const elm = getOverlay("createCourse");
|
||||
const inputs = elm.getElementsByTagName("input");
|
||||
const description = elm.getElementsByTagName("textarea")[0];
|
||||
|
||||
const title = inputs[0].value.toLowerCase().trim();
|
||||
if (title.length == 0) {
|
||||
alert("Kursname darf nicht leer sein");
|
||||
return;
|
||||
}
|
||||
|
||||
const courseId = title.replace(/\s+/g, "_");
|
||||
|
||||
const sDateInp = inputs[inputs.length-2];
|
||||
const eDateInp = inputs[inputs.length-1];
|
||||
|
||||
const data = {
|
||||
"title": title,
|
||||
"description": description.value,
|
||||
"owner": userData.name,
|
||||
"questions": [],
|
||||
"result": [],
|
||||
"result_history": [],
|
||||
"start_date": sDateInp.value || "",
|
||||
"expire_date": eDateInp.value || ""
|
||||
};
|
||||
|
||||
const evaluations = elm.querySelector(".evaluations > div");
|
||||
const questions = [];
|
||||
for (var i of evaluations.getElementsByClassName("evaluation")) {
|
||||
const inpE = i.querySelector("input");
|
||||
const selE = i.querySelector("select");
|
||||
if (inpE.value.length == 0) continue;
|
||||
|
||||
questions.push({
|
||||
"title": inpE.value,
|
||||
"type": selE.value
|
||||
});
|
||||
}
|
||||
data.questions = questions;
|
||||
evaluations.remove();
|
||||
|
||||
await couchDB.set("course:" + courseId, data);
|
||||
|
||||
const users = await couchDB.get("users");
|
||||
users[userData.name].courses.push(courseId);
|
||||
await couchDB.set("users", users);
|
||||
|
||||
hideOverlay("createCourse");
|
||||
location.reload();
|
||||
}
|
||||
|
||||
async function showCourseCreation() {
|
||||
showOverlay("createCourse");
|
||||
}
|
||||
|
||||
let confirmReturn = null;
|
||||
|
||||
function showConfirm(onYes) {
|
||||
confirmReturn = onYes;
|
||||
showOverlay("deletionConfirmation")
|
||||
}
|
||||
|
||||
function confirmYes() {
|
||||
hideOverlay("deletionConfirmation")
|
||||
if (confirmReturn) {
|
||||
confirmReturn()
|
||||
}
|
||||
confirmReturn = null;
|
||||
}
|
||||
|
||||
function confirmNo() {
|
||||
hideOverlay("deletionConfirmation")
|
||||
confirmReturn = null;
|
||||
}
|
||||
|
||||
async function deleteCourse(courseId) {
|
||||
showConfirm(
|
||||
async() => {
|
||||
await couchDB.delete("course:" + courseId);
|
||||
|
||||
const users = await couchDB.get("users");
|
||||
users[userData.name].courses = users[userData.name].courses.filter(id => id !== courseId);
|
||||
await couchDB.set("users", users);
|
||||
|
||||
location.reload();
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<!--Implementiere hier dein Zeugs-->
|
||||
|
||||
<style>
|
||||
.edit_course {
|
||||
min-width: 70% !important;
|
||||
}
|
||||
.edit_course input {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
padding: 4px;
|
||||
background: none;
|
||||
border: 1px solid black;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.edit_course textarea {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
resize: none;
|
||||
padding: 4px;
|
||||
background: none;
|
||||
border: 1px solid black;
|
||||
height: 100px;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.edit_course .evaluations {
|
||||
overflow-y: auto;
|
||||
text-align: center;
|
||||
max-height: 300px;
|
||||
border: 2px solid grey;
|
||||
padding: 10px;
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
.edit_course .evaluations .evaluation {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid black;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
margin-bottom: 10px;
|
||||
position: relative;
|
||||
}
|
||||
.edit_course .evaluation input {
|
||||
display: inline-block;
|
||||
font-size: 20px !important;
|
||||
width: calc(100% - 80px);
|
||||
}
|
||||
.edit_course .evaluation > select {
|
||||
width: 90%;
|
||||
font-size: 18px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.edit_course .evaluation > button {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
font-size: 23px;
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 5px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.edit_course > button {
|
||||
width: 100%;
|
||||
font-size: 18px;
|
||||
border-radius: var(--border-radius);
|
||||
padding: 4px;
|
||||
font-weight: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
<overlay id="edit_course">
|
||||
<input placeholder="Kursname" style="width: calc(100% - 50px);"><br><br>
|
||||
Beschreibung:
|
||||
<textarea placeholder="Beschreibung"></textarea><br><br>
|
||||
Feedback-Fragen:
|
||||
<div class="evaluations">
|
||||
<div></div>
|
||||
<button class="add_button" onclick="createNewEvaluation()">+</button>
|
||||
</div><br>
|
||||
Start-Termin: <input type="date" style="margin-bottom: 5px;"><br>
|
||||
Abgabe-Termin: <input type="date"><br><br>
|
||||
<button onclick="saveEditCourse()">Speichern</button>
|
||||
</overlay>
|
||||
|
||||
<script>
|
||||
|
||||
async function showEditCourse(name) { //
|
||||
const data = await couchDB.get("course:" + name);
|
||||
/*if (data.owner != userData.name) {
|
||||
console.error("User is not author");
|
||||
return;
|
||||
}*/
|
||||
|
||||
showOverlay("edit_course");
|
||||
|
||||
const elm = getOverlay("edit_course");
|
||||
|
||||
const inputs = elm.getElementsByTagName("input");
|
||||
const description = elm.getElementsByTagName("textarea")[0];
|
||||
|
||||
inputs[0].value = data.title;
|
||||
inputs[0].setAttribute("oldID", name);
|
||||
description.value = data.description;
|
||||
|
||||
const sDateInp = inputs[inputs.length-2];
|
||||
const eDateInp = inputs[inputs.length-1];
|
||||
|
||||
sDateInp.value = data["start_date"] ?? "";
|
||||
eDateInp.value = data["expire_date"] ?? "";
|
||||
|
||||
const evaluations = elm.querySelector(".evaluations > div");
|
||||
|
||||
for (var i of data.questions) {
|
||||
evaluations.appendChild(createEvaluation(i));
|
||||
}
|
||||
}
|
||||
function createNewEvaluation() {
|
||||
const elm = getOverlay("edit_course");
|
||||
if (elm == null) return;
|
||||
|
||||
const evaluations = elm.querySelector(".evaluations > div");
|
||||
evaluations.appendChild(
|
||||
createEvaluation({
|
||||
"title": "", "type": "text"
|
||||
})
|
||||
);
|
||||
}
|
||||
function createEvaluation(question) {
|
||||
const div = document.createElement("div");
|
||||
div.classList.add("evaluation");
|
||||
div.innerHTML = `
|
||||
<button onclick="this.parentElement.remove();">🗑</button>
|
||||
<input value="${question.title}">
|
||||
<select>
|
||||
<option value="text" ${question.type == "text" ? "selected": ""}>Text</option>
|
||||
<option value="scala" ${question.type == "scala" ? "selected": ""}>Scala</option>
|
||||
<!--<option value="emoji" ${question.type == "emoji" ? "selected": ""}>Emoji</option>-->
|
||||
</select>
|
||||
`;
|
||||
return div;
|
||||
}
|
||||
async function saveEditCourse() {
|
||||
const elm = getOverlay("edit_course");
|
||||
const inputs = elm.getElementsByTagName("input");
|
||||
const description = elm.getElementsByTagName("textarea")[0];
|
||||
|
||||
const oldID = inputs[0].getAttribute("oldID");
|
||||
const data = await couchDB.get("course:" + oldID);
|
||||
|
||||
data["title"] = inputs[0].value;
|
||||
data["description"] = description.value;
|
||||
|
||||
const evaluations = elm.querySelector(".evaluations > div");
|
||||
const questions = [];
|
||||
for (var i of evaluations.getElementsByClassName("evaluation")) {
|
||||
const inpE = i.querySelector("input");
|
||||
const selE = i.querySelector("select");
|
||||
if (inpE.value.length == 0) continue;
|
||||
|
||||
questions.push({
|
||||
"title": inpE.value,
|
||||
"type": selE.value
|
||||
});
|
||||
}
|
||||
data["questions"] = questions;
|
||||
evaluations.remove();
|
||||
|
||||
const sDateInp = inputs[inputs.length-2];
|
||||
const eDateInp = inputs[inputs.length-1];
|
||||
|
||||
if (sDateInp.value.length > 0) {
|
||||
let dateObject = new Date(sDateInp.value);
|
||||
let dateString = dateObject.toISOString().split('T')[0];
|
||||
data["start_date"] = dateString;
|
||||
} if (eDateInp.value.length > 0) {
|
||||
let dateObject = new Date(eDateInp.value);
|
||||
let dateString = dateObject.toISOString().split('T')[0];
|
||||
data["expire_date"] = dateString;
|
||||
}
|
||||
|
||||
|
||||
await couchDB.set("course:" + oldID, data);
|
||||
|
||||
hideOverlay("edit_course");
|
||||
setCourseView();
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user