schönes Siegerpodest (und bessere Punkteübersicht)
This commit is contained in:
@@ -153,7 +153,7 @@
|
||||
{% if request.session.mode == "learn" %}
|
||||
<form action="">
|
||||
<input id="textanswer" type="text" placeholder="DEINE ANTWORT"
|
||||
class="answer-option text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option lg:w-80 dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a] ">
|
||||
class="answer-option text-center mb-4 p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option lg:w-80 dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a] ">
|
||||
|
||||
<button
|
||||
onclick="submitAnswer( -1 );"
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
{% elif question_data.type == "input" %}
|
||||
<form action="">
|
||||
<input id="textanswer" type="text" placeholder="DEINE ANTWORT"
|
||||
class="answer-option text-center p-2 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option lg:w-80 dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a]">
|
||||
class="answer-option text-center p-2 mb-4 bg-gray-100 hover:bg-blue-100 rounded-lg transition-colors duration-200 answer-option lg:w-80 dark:bg-transparent dark:text-white dark:hover:bg-[#2a2f3a]">
|
||||
<button
|
||||
onclick="submitAnswer( -1 );"
|
||||
class="px-6 py-2 bg-blue-500 hover:bg-blue-600 text-white font-semibold rounded-lg transition-colors duration-200 answer-option "
|
||||
@@ -318,6 +318,7 @@ function updateOrderNumbers() {
|
||||
|
||||
|
||||
function submitOrderAnswer() {
|
||||
if (hasAnswered) return;
|
||||
const order_button=document.getElementById("send_order")
|
||||
order_button.disabled=true;
|
||||
order_button.classList.add('opacity-50');
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6 dark:bg-transparent dark:text-white">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6 dark:bg-transparent dark:text-white ">
|
||||
<h1 class="text-3xl font-bold mb-6">Ergebnisse</h1>
|
||||
|
||||
{% if request.session.mode == "learn" or is_host %}
|
||||
<div class="mb-6">
|
||||
|
||||
<h2 class="text-xl font-bold mb-4">Aktuelle Frage</h2>
|
||||
@@ -64,61 +64,58 @@
|
||||
<p class="text-gray-600" id="option-count-1">0 Antworten</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% else %}
|
||||
|
||||
|
||||
<div class="flex flex-col items-center justify-center text-center pt-4">
|
||||
{% if participant.last_answer_correct %}
|
||||
<!-- Richtig-Symbol -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor"
|
||||
class="text-green-500 size-40">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="M9 12.75 11.25 15 15 9.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
|
||||
<!-- Feedback-Text -->
|
||||
<div id="antwort-richtig"
|
||||
class="pt-3 text-gray-600 dark:text-white font-bold max-w-xs md:max-w-sm">
|
||||
Hier erscheint gleich dein Feedback...
|
||||
</div>
|
||||
|
||||
{% elif participant.last_answer_correct == False %}
|
||||
<!-- Falsch-Symbol -->
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"
|
||||
stroke-width="1.5" stroke="currentColor"
|
||||
class="text-red-500 size-40">
|
||||
<path stroke-linecap="round" stroke-linejoin="round"
|
||||
d="m9.75 9.75 4.5 4.5m0-4.5-4.5 4.5M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
|
||||
</svg>
|
||||
|
||||
<!-- Feedback-Text -->
|
||||
<div id="antwort-falsch"
|
||||
class="pt-3 text-gray-600 dark:text-white font-bold max-w-xs md:max-w-sm">
|
||||
Hier erscheint gleich dein Feedback...
|
||||
</div>
|
||||
{% endif %}
|
||||
<p class="text-blue-600 font-bold text-md">+{{ participant.last_score }} Punkte</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="mb-6">
|
||||
{% if request.session.mode == "learn" %}
|
||||
<h2 class="text-xl font-bold mb-4">Punktestand</h2>
|
||||
|
||||
{% if is_last_question and request.session.mode != "learn" %}
|
||||
<!-- Siegerpodest -->
|
||||
<div class="flex justify-center items-end gap-4 mb-8">
|
||||
|
||||
<!-- Platz 2 links -->
|
||||
{% with participant=participants.1 %}
|
||||
<div class="flex flex-col items-center break-words">
|
||||
<span class="display_name text-gray-600 font-black text-2xl dark:text-white " id="display_name-1">{{ participant.display_name }}</span>
|
||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="dark:text-white text-gray-600 font-bold show-score text-md" id="score-1">{{ participant.score }}</p>
|
||||
<div class="h-40 w-24 rounded-t-md font-bold text-center text-base shadow-lg bg-gradient-to-b from-gray-400 via-gray-300 to-gray-300 flex flex-col items-center justify-center text-black dark:text-white cursor-pointer leading-tight">
|
||||
<span class="size-10 rounded-full bg-white text-black text-center flex items-center justify-center font-bold text-3xl">🥈</span><br>{{ participant.display_name }}
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
<!-- Platz 1 mitte -->
|
||||
{% with participant=participants.0 %}
|
||||
|
||||
<div class="flex flex-col items-center break-words">
|
||||
<span class="display_name text-gray-600 font-black text-2xl dark:text-white" id="display_name-0">{{ participant.display_name }}</span>
|
||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="dark:text-white text-gray-600 font-bold show-score text-md" id="score-0">{{ participant.score }}</p>
|
||||
<div class="h-64 w-24 rounded-t-md font-bold text-center text-base shadow-lg bg-gradient-to-b from-yellow-400 via-yellow-300 to-yellow-600 flex flex-col items-center justify-center text-black dark:text-white cursor-pointer leading-tight">
|
||||
<span class="size-12 rounded-full bg-white text-black text-center flex items-center justify-center font-bold text-4xl"> 🥇</span><br>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
<!-- Platz 3 rechts -->
|
||||
{% with participant=participants.2 %}
|
||||
<div class="flex flex-col items-center break-words">
|
||||
<span class="display_name text-gray-600 font-black text-2xl dark:text-white " id="display_name-2">{{ participant.display_name }}</span>
|
||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="dark:text-white text-gray-600 font-bold show-score text-md" id="score-2">{{ participant.score }}</p>
|
||||
<div class="h-30 w-24 rounded-t-md font-bold text-center text-base shadow-lg bg-gradient-to-b from-orange-500 via-orange-400 to-orange-700 flex flex-col items-center justify-center text-black dark:text-white cursor-pointer leading-tight">
|
||||
<span class="size-10 rounded-full bg-white text-black text-center flex items-center justify-center font-bold text-3xl ">🥉</span><br>{{ participant.display_name }}
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
<div id="scoreboard" class="leading-relaxed">
|
||||
{% for participant in participants %}
|
||||
{% if not is_last_question or request.session.mode == "learn" %}
|
||||
{% if request.session.mode == "learn" %}
|
||||
{% if participant == my_participant or is_host %}
|
||||
<div class="dark:bg-transparent mt-2 shadow-sm p-4 bg-gray-100 rounded-lg border-2 border {% if forloop.counter <= 3 %}border-yellow-500{% else %}border-transparent{% endif %}">
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
@@ -189,13 +186,29 @@
|
||||
|
||||
{% if is_host %}
|
||||
{% if is_last_question %}
|
||||
{% if is_last_question and request.session.mode != "learn" %}
|
||||
<button id="winner-button" class="mt-4 w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
Siegerpodest
|
||||
</button>
|
||||
|
||||
{% else %}
|
||||
<button id="finish-button" class="mt-4 w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
Quiz beenden
|
||||
</button>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<button id="next-button" class="mt-4 w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
{% if request.session.mode == "learn" %}
|
||||
<button id="next-button" class="mt-4 w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
Nächste Frage
|
||||
|
||||
</button>
|
||||
{% else %}
|
||||
<button id="scoreboard-button" class="mt-4 w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
Punkteübersicht
|
||||
|
||||
</button>
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
@@ -205,23 +218,6 @@
|
||||
{% block extra_js %}
|
||||
{% if is_last_question %}
|
||||
|
||||
<script>
|
||||
// Hilfsfunktion für Pausen
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
|
||||
function triggerConfetti() {
|
||||
const end = Date.now() + 15 * 1000;
|
||||
(function frame() {
|
||||
confetti({ particleCount: 2, angle: 60, spread: 55, origin: { x: 0 } });
|
||||
confetti({ particleCount: 2, angle: 120, spread: 55, origin: { x: 1 } });
|
||||
if (Date.now() < end) requestAnimationFrame(frame);
|
||||
})();
|
||||
}
|
||||
triggerConfetti();
|
||||
</script>
|
||||
{% endif %}
|
||||
{% include 'play/game/common_scripts.html' %}
|
||||
{% if is_host %}
|
||||
@@ -232,6 +228,16 @@
|
||||
|
||||
|
||||
<script>
|
||||
|
||||
|
||||
function triggerConfetti() {
|
||||
const end = Date.now() + 30 * 1000;
|
||||
(function frame() {
|
||||
confetti({ particleCount: 2, angle: 60, spread: 55, origin: { x: 0 } });
|
||||
confetti({ particleCount: 2, angle: 120, spread: 55, origin: { x: 1 } });
|
||||
if (Date.now() < end) requestAnimationFrame(frame);
|
||||
})();
|
||||
}
|
||||
async function start() {
|
||||
|
||||
elements=document.getElementsByClassName("show-score");
|
||||
@@ -269,6 +275,9 @@
|
||||
{% if is_last_question %}
|
||||
start();
|
||||
bounce();
|
||||
{% if request.session.mode == "learn" %}
|
||||
triggerConfetti();
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% else %}
|
||||
@@ -348,10 +357,11 @@ if (antwortRichtig) {
|
||||
gameSocket.onmessage = function(e) {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.type === 'game_state_update' &&
|
||||
data.redirect_url &&
|
||||
(data.action === 'next_question' || data.action === 'finish_game')) {
|
||||
window.location.href = data.redirect_url;
|
||||
} else if (data.type === 'answer_stats') {
|
||||
data.redirect_url &&
|
||||
(data.action === 'next_question' || data.action === 'finish_game' || data.action === 'show_winner_podest'|| data.action === 'show_scoreboard')) {
|
||||
window.location.href = data.redirect_url;
|
||||
}
|
||||
else if (data.type === 'answer_stats') {
|
||||
updateAnswerStats(data.stats);
|
||||
}
|
||||
};
|
||||
@@ -377,7 +387,30 @@ if (antwortRichtig) {
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
var podestButton = document.getElementById('winner-button');
|
||||
if (podestButton) {
|
||||
podestButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'winner_podest',
|
||||
'host_id': hostId
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
{% else %}
|
||||
|
||||
var scoreboardButton = document.getElementById('scoreboard-button');
|
||||
if (scoreboardButton) {
|
||||
scoreboardButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'scoreboard',
|
||||
'host_id': hostId
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var nextButton = document.getElementById('next-button');
|
||||
if (nextButton) {
|
||||
nextButton.addEventListener('click', function() {
|
||||
|
||||
310
django/templates/play/game/scoreboard.html
Normal file
310
django/templates/play/game/scoreboard.html
Normal file
@@ -0,0 +1,310 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6 dark:bg-transparent dark:text-white">
|
||||
<h1 class="text-3xl font-bold mb-6">Ergebnisse</h1>
|
||||
|
||||
|
||||
|
||||
<div class="mb-6">
|
||||
{% if request.session.mode != "learn" %}
|
||||
<h2 class="text-xl font-bold mb-4">Punktestand</h2>
|
||||
{% endif %}
|
||||
|
||||
<div id="scoreboard" class="leading-relaxed">
|
||||
{% for participant in participants %}
|
||||
{% if request.session.mode != "learn" %}
|
||||
{% if participant == my_participant or is_host %}
|
||||
<div class="dark:bg-transparent mt-2 shadow-sm p-4 bg-gray-100 rounded-lg border-2 border
|
||||
{% if forloop.counter <= 3 %}
|
||||
{% if forloop.counter == 1 %}border-yellow-400{% endif %}
|
||||
{% if forloop.counter == 2 %}border-gray-400{% endif %}
|
||||
{% if forloop.counter == 3 %}border-orange-400{% endif %}
|
||||
{% else %}
|
||||
border-transparent{% endif %}">
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<div class="text-4xl font-bold flex items-center gap-2">
|
||||
{% if forloop.counter == 1 %}
|
||||
🥇
|
||||
{% elif forloop.counter == 2 %}
|
||||
🥈
|
||||
{% elif forloop.counter == 3 %}
|
||||
🥉
|
||||
{% else %}
|
||||
{{ forloop.counter }}.
|
||||
{% endif %}
|
||||
<span class="display_name text-gray-600 font-black text-3xl dark:text-white " id="display_name-{{ forloop.counter0 }}">{{ participant.display_name }}</span>
|
||||
</div class="flex flex-col items-start">
|
||||
|
||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="dark:text-white text-gray-600 font-bold show-score text-xl" id="score-{{ forloop.counter0 }}">{{ participant.score }} Punkte</p>
|
||||
{% if participant == my_participant or request.session.mode == "learn"%}
|
||||
<p class="text-blue-600 font-bold text-md">+{{ participant.last_score }} Punkte</p>
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if is_host %}
|
||||
{% if is_last_question %}
|
||||
{% if is_last_question and request.session.mode != "learn" %}
|
||||
<button id="winner-button" class="mt-4 w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
Siegerpodest
|
||||
</button>
|
||||
|
||||
{% else %}
|
||||
<button id="finish-button" class="mt-4 w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
Quiz beenden
|
||||
</button>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
|
||||
<button id="next-button" class="mt-4 w-full p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
Nächste Frage
|
||||
|
||||
</button>
|
||||
|
||||
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
{% if is_last_question %}
|
||||
|
||||
{% endif %}
|
||||
{% include 'play/game/common_scripts.html' %}
|
||||
{% if is_host %}
|
||||
{% include 'play/game/sound.html' %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
async function start() {
|
||||
|
||||
elements=document.getElementsByClassName("show-score");
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
const el = elements[i];
|
||||
|
||||
let counter=Number(el.getAttribute('data-score'))-Number(el.getAttribute('data-last-score'));
|
||||
let goal=Number(el.getAttribute('data-score'));
|
||||
let interval= setInterval(function(){
|
||||
el.innerHTML = counter + " Punkte";
|
||||
|
||||
|
||||
if(counter<=goal){
|
||||
el.innerHTML = counter + " Punkte";
|
||||
counter+=8;
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
el.innerHTML = goal + " Punkte";
|
||||
clearInterval(interval);
|
||||
}
|
||||
|
||||
}, 20);}}
|
||||
|
||||
function bounce(){
|
||||
|
||||
const names = document.getElementsByClassName("display_name");
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
names[i].classList.add("animate-bounce");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{% if is_last_question %}
|
||||
start();
|
||||
bounce();
|
||||
|
||||
|
||||
{% else %}
|
||||
start();
|
||||
{% endif %}
|
||||
|
||||
const richtigeAntworten = [
|
||||
"Deine Antwort ist nicht falsch. Sie ist richtig!",
|
||||
"Ja, du kannst es!",
|
||||
"So kann es weiter gehen.",
|
||||
"Ja, deine Antwort ist korrekt. Was soll ich dazu noch sagen? SUPER!",
|
||||
"SUPER GUT.",
|
||||
"Volltreffer!",
|
||||
"Bravo! Das sitzt!",
|
||||
"Na bitte, geht doch!",
|
||||
"Schön. Einfach schön.",
|
||||
"Exzellent kombiniert, Sherlock!",
|
||||
"Punkt für dich!",
|
||||
"Das war meisterhaft.",
|
||||
"Korrekt - du scheinst das zu können!",
|
||||
"So sieht Erfolg aus!",
|
||||
"Glänzend gelöst!",
|
||||
"Das war keine Glückssache - das war Können!",
|
||||
"Treffer, versenkt!",
|
||||
"Du hast es drauf!",
|
||||
"Da merkt man: Profi am Werk.",
|
||||
"Richtige Antwort - dafür gibt es viele Punkte!",
|
||||
"Weiter so!",
|
||||
"Wow - das war richtig gut!"
|
||||
];
|
||||
|
||||
const falscheAntworten = [
|
||||
"Oops! War wohl nicht dein Tag.",
|
||||
"Knapp daneben ist auch vorbei!",
|
||||
"Das war... kreativ!",
|
||||
"Wenn man schon alles wüsste, wäre das Quiz doch sinnlos.",
|
||||
"Deine Antwort war einzigartig - leider falsch!",
|
||||
"Na gut, wenigstens hast du es probiert.",
|
||||
"Das war eine interessante Theorie...",
|
||||
"Ein Genie irrt sich auch mal.",
|
||||
"Eine gute Antwort - aber nicht auf diese Frage.",
|
||||
"Das ist leider falsch. Mehr gibt es nicht zu sagen.",
|
||||
"Gute Idee! Aber leider nicht richtig.",
|
||||
"Oh weh! Ein Fehler. Naja, einer ist keiner.",
|
||||
"Die Antwort klang richtig, sie ist es aber nicht.",
|
||||
"Interessanter Ansatz. Nicht hilfreich, aber interessant.",
|
||||
"Nenn das lieber „alternative Fakten“.",
|
||||
"Du hast die richtige Antwort doch gewusst: 'Die Seite hat nur nicht geladen.'",
|
||||
"Jeder fängt mal klein an!",
|
||||
"Kopf hoch - weiter geht's!",
|
||||
"Nobody is perfect!",
|
||||
"Du schaffst das - vielleicht ab jetzt.",
|
||||
"Falsche Antwort, aber guter Wille!",
|
||||
"Übung macht den Quiz-Meister.",
|
||||
"Beim nächsten Mal triffst du!",
|
||||
"Das war nur zum Aufwärmen, oder?",
|
||||
"Kein Problem - weiter geht's.",
|
||||
"Gute Frage - aber falsche Antwort."
|
||||
];
|
||||
|
||||
|
||||
const antwortRichtig = document.getElementById("antwort-richtig");
|
||||
const antwortFalsch = document.getElementById("antwort-falsch");
|
||||
|
||||
if (antwortRichtig) {
|
||||
antwortRichtig.textContent = richtigeAntworten[Math.floor(Math.random() * richtigeAntworten.length)];
|
||||
} else if (antwortFalsch) {
|
||||
antwortFalsch.textContent = falscheAntworten[Math.floor(Math.random() * falscheAntworten.length)];
|
||||
}
|
||||
const joinCode = '{{ quiz_game.join_code }}';
|
||||
const hostId = '{{ host_id }}';
|
||||
const wsScheme = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const gameSocket = new WebSocket(
|
||||
`${wsScheme}://${window.location.host}/ws/game/${joinCode}/`
|
||||
);
|
||||
|
||||
gameSocket.onmessage = function(e) {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.type === 'game_state_update' &&
|
||||
data.redirect_url &&
|
||||
(data.action === 'next_question' || data.action === 'finish_game' || data.action === 'show_winner_podest'|| data.action === 'show_scoreboard')) {
|
||||
window.location.href = data.redirect_url;
|
||||
}
|
||||
else if (data.type === 'answer_stats') {
|
||||
updateAnswerStats(data.stats);
|
||||
}
|
||||
};
|
||||
|
||||
gameSocket.onclose = function(e) {
|
||||
// Normal closure (code 1000) oder Navigation zu einer anderen Seite (code 1001)
|
||||
if (e.code === 1000 || e.code === 1001) {
|
||||
console.log('Game socket closed normally');
|
||||
} else {
|
||||
console.error('Game socket closed unexpectedly', e.code);
|
||||
}
|
||||
};
|
||||
|
||||
{% if is_host %}
|
||||
// Add click handlers for host buttons
|
||||
{% if is_last_question %}
|
||||
var finishButton = document.getElementById('finish-button');
|
||||
if (finishButton) {
|
||||
finishButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'finish_game',
|
||||
'host_id': hostId
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
var podestButton = document.getElementById('winner-button');
|
||||
if (podestButton) {
|
||||
podestButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'winner_podest',
|
||||
'host_id': hostId
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
{% else %}
|
||||
|
||||
var scoreboardButton = document.getElementById('scoreboard-button');
|
||||
if (scoreboardButton) {
|
||||
scoreboardButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'scoreboard',
|
||||
'host_id': hostId
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var nextButton = document.getElementById('next-button');
|
||||
if (nextButton) {
|
||||
nextButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'next_question',
|
||||
'host_id': hostId
|
||||
}));
|
||||
}, { once: true });
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
function updateAnswerStats(stats) {
|
||||
const total = Object.values(stats).reduce((a, b) => a + b, 0) || 1;
|
||||
|
||||
for (var optionIndex in stats) {
|
||||
if (stats.hasOwnProperty(optionIndex)) {
|
||||
var countElement = document.getElementById('option-count-' + optionIndex);
|
||||
var fillElement = document.getElementById('option-fill-' + optionIndex);
|
||||
|
||||
if (countElement) {
|
||||
countElement.textContent = stats[optionIndex] + ' Antwort(en)';
|
||||
}
|
||||
|
||||
if (fillElement) {
|
||||
const percentage = Math.round((stats[optionIndex] / total) * 100);
|
||||
fillElement.style.width = percentage + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Request answer stats when page loads
|
||||
gameSocket.onopen = function(e) {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'get_answer_stats'
|
||||
}));
|
||||
};
|
||||
</script>
|
||||
{% endblock %}
|
||||
594
django/templates/play/game/winner_podest.html
Normal file
594
django/templates/play/game/winner_podest.html
Normal file
@@ -0,0 +1,594 @@
|
||||
{% extends 'base.html' %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
{% if is_last_question and is_host %}
|
||||
<!-- Siegerpodest -->
|
||||
<div class="min-h-screen">
|
||||
<h2 class="w-full flex justify-center dark:text-white font-bold text-2xl ">🏆 Siegerpodest</h2>
|
||||
<h4 class="w-full flex justify-center dark:text-white font-bold">Wer ist hier der Quiz-Master? </h4>
|
||||
|
||||
{% with participant=participants.0 %}
|
||||
<div class="w-full flex justify-center">
|
||||
<h1 id="winner-text" class="bg-gradient-to-r from-yellow-400 via-yellow-300 to-yellow-600 bg-clip-text text-transparent font-bold hidden animate-ping px-2 max-w-screen-sm text-center break-words">
|
||||
Glückwunsch, {{ participant.display_name }}!
|
||||
</h1>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div id="podest-container" class="w-full absolute bottom-0 flex justify-center items-end gap-2 md:gap-4 mb-2 dark:text-white">
|
||||
|
||||
|
||||
<!-- Platz 2 links -->
|
||||
{% with participant=participants.1 %}
|
||||
<div class="flex flex-col shrink items-center break-words max-w-[6rem] md:max-w-[8rem] lg:max-w-[10rem] overflow-x-auto pt-10">
|
||||
<span class="display_name p-2 text-gray-600 font-black text-xl md:text-2xl lg:text-3xl opacity-0 transition-opacity duration-1000 dark:text-white hyphens-auto" id="display_name-1">{{ participant.display_name }}</span>
|
||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="opacity-0 transition-opacity duration-1000 dark:text-white font-bold show-score text-sm md:text-lg lg:text-xl text-gray-400" id="score-1">{{ participant.score }}</p>
|
||||
<div data-final-height="33" id="podium-1" class="border-2 border-gray-200 transition-all duration-1000 ease-out overflow-hidden podium h-24 md:h-[12rem] lg:h-[16rem] w-24 md:w-32 lg:w-40 rounded-t-md font-bold text-center text-base shadow-lg bg-gradient-to-b from-gray-400 via-gray-300 to-gray-300 flex flex-col items-center justify-center text-black dark:text-white cursor-pointer leading-tight">
|
||||
<span class="size-10 md:size-18 rounded-full bg-white text-black text-center flex items-center justify-center font-bold text-3xl md:text-5xl lg:text-6xl">🥈</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
<!-- Platz 1 mitte -->
|
||||
{% with participant=participants.0 %}
|
||||
<div class="flex flex-col shrink items-center break-words max-w-[6rem] md:max-w-[8rem] lg:max-w-[10rem] overflow-x-auto pt-10">
|
||||
<div id="resultFirst"></div>
|
||||
<span class="display_name p-2 text-gray-600 font-black text-xl md:text-3xl lg:text-4xl opacity-0 transition-opacity duration-1000 bg-gradient-to-r from-yellow-400 via-yellow-300 to-yellow-600 bg-clip-text text-transparent hyphens-auto" id="display_name-0">{{ participant.display_name }}</span>
|
||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="opacity-0 transition-opacity duration-1000 dark:text-white text-yellow-500 font-bold show-score text-sm md:text-lg lg:text-xl" id="score-0">{{ participant.score }}</p>
|
||||
<div data-final-height="45" id="podium-0" class="border-2 border-yellow-500 transition-all duration-1000 ease-out overflow-hidden podium h-32 md:h-[16rem] lg:h-[22rem] w-24 md:w-32 lg:w-40 rounded-t-md font-bold text-center text-base shadow-lg bg-gradient-to-b from-yellow-400 via-yellow-300 to-yellow-600 flex flex-col items-center justify-center text-black dark:text-white cursor-pointer leading-tight">
|
||||
<span id="firstMedal" class="size-12 md:size-22 rounded-full bg-white text-black text-center flex items-center justify-center font-bold text-4xl md:text-6xl lg:text-7xl">🥇</span><br>
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
<!-- Platz 3 rechts -->
|
||||
{% with participant=participants.2 %}
|
||||
<div class="flex flex-col shrink items-center break-words max-w-[6rem] md:max-w-[8rem] lg:max-w-[10rem] overflow-x-auto pt-10">
|
||||
<span class="display_name p-2 text-gray-600 font-black text-xl md:text-2xl lg:text-3xl dark:text-white opacity-0 transition-opacity duration-1000 hyphens-auto" id="display_name-2">{{ participant.display_name }}</span>
|
||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="opacity-0 transition-opacity duration-1000 dark:text-white text-orange-500 font-bold show-score text-sm md:text-lg lg:text-xl" id="score-2">{{ participant.score }}</p>
|
||||
<div data-final-height="25" id="podium-2" class="border-2 border-orange-500 transition-all duration-1000 ease-out overflow-hidden podium h-20 md:h-[10rem] lg:h-[14rem] w-24 md:w-32 lg:w-40 rounded-t-md font-bold text-center text-base shadow-lg bg-gradient-to-b from-orange-500 via-orange-400 to-orange-700 flex flex-col items-center justify-center text-black dark:text-white cursor-pointer leading-tight">
|
||||
<span class="size-10 md:size-18 rounded-full bg-white text-black text-center flex items-center justify-center font-bold text-3xl md:text-5xl lg:text-6xl">🥉</span>
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div id="thanks" class="hidden -mt-10">
|
||||
<div class="w-full flex justify-center">
|
||||
<h1 class="bg-gradient-to-r from-yellow-400 via-yellow-300 to-yellow-600 bg-clip-text text-transparent font-bold px-2 max-w-screen-sm text-center break-words">
|
||||
Vielen Dank fürs Spielen!
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-center">
|
||||
<button id="finish-button" class=" w-3/4 md:w-1/2 bottom-0 left-0 p-3 rounded-full bg-blue-600 text-white font-bold hover:bg-blue-700 transition-colors duration-200">
|
||||
Quiz beenden
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% else %}
|
||||
|
||||
|
||||
<div class="container mx-auto px-4">
|
||||
|
||||
|
||||
{% with participant=participants.0 %}
|
||||
<div class="w-full flex justify-center">
|
||||
<h1 id="winner-text" class="bg-gradient-to-r from-yellow-400 via-yellow-300 to-yellow-600 bg-clip-text text-transparent font-bold hidden animate-ping px-2 max-w-screen-sm text-center break-words">
|
||||
Glückwunsch, {{ participant.display_name }}!
|
||||
</h1>
|
||||
</div>
|
||||
{% endwith %}
|
||||
|
||||
<div class="bg-white rounded-lg shadow-md p-6 mb-6 dark:bg-transparent dark:text-white">
|
||||
<h1 id="result-text" class="text-3xl w-full flex justify-center dark:text-white font-bold">🏆 Wer ist hier der Quiz-Master?</h1>
|
||||
|
||||
<h4 id="info" class="mt-4 w-full flex justify-center dark:text-white font-bold">Nach der Siegerehrung siehst du deine Platzierung!</h4>
|
||||
|
||||
|
||||
|
||||
<div id="participant-score" class="mb-6 ">
|
||||
|
||||
|
||||
<div id="scoreboard" class="leading-relaxed">
|
||||
{% for participant in participants %}
|
||||
{% if request.session.mode != "learn" %}
|
||||
{% if participant == my_participant or is_host %}
|
||||
<div id="player_score" class="hidden dark:bg-transparent mt-2 shadow-sm p-4 bg-gray-100 rounded-lg border-2 border {% if forloop.counter <= 3 %}
|
||||
{% if forloop.counter == 1 %}border-yellow-400{% endif %}
|
||||
{% if forloop.counter == 2 %}border-gray-400{% endif %}
|
||||
{% if forloop.counter == 3 %}border-orange-400{% endif %}
|
||||
{% else %}
|
||||
border-transparent{% endif %}">
|
||||
<div class="flex flex-col items-start gap-1">
|
||||
<div class="text-4xl font-bold flex items-center gap-2">
|
||||
{% if forloop.counter == 1 %}
|
||||
🥇
|
||||
{% elif forloop.counter == 2 %}
|
||||
🥈
|
||||
{% elif forloop.counter == 3 %}
|
||||
🥉
|
||||
{% else %}
|
||||
{{ forloop.counter }}.
|
||||
{% endif %}
|
||||
<span class="display_name text-gray-600 font-black text-3xl dark:text-white " id="display_name-{{ forloop.counter0 }}">{{ participant.display_name }}</span>
|
||||
</div class="flex flex-col items-start">
|
||||
|
||||
<p data-score="{{ participant.score }}" data-last-score="{{ participant.last_score }}" class="dark:text-white text-gray-600 font-bold show-score text-xl" id="score-{{ forloop.counter0 }}">{{ participant.score }} Punkte</p>
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
<style>
|
||||
.podium {
|
||||
height: 0;
|
||||
|
||||
}
|
||||
.spotlight-wrapper::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -800px; /* Start oben außerhalb */
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 15rem;
|
||||
height: 700px;
|
||||
pointer-events: none;
|
||||
|
||||
background: radial-gradient(
|
||||
ellipse 60% 100% at center bottom,
|
||||
rgba(254, 254, 178, 0.9) 0%,
|
||||
rgba(252, 236, 132, 0.7) 25%,
|
||||
rgba(255, 230, 130, 0.5) 55%,
|
||||
rgba(255, 210, 100, 0.1) 85%,
|
||||
rgba(255, 180, 70, 0) 100%
|
||||
);
|
||||
|
||||
filter: blur(24px) brightness(1.2);
|
||||
opacity: 0; /* Start unsichtbar */
|
||||
animation: slideInOutSpotlight 6s ease forwards , fadeOutSpotlight 6s 6s ease forwards; /* Dauer anpassen */
|
||||
z-index: -1;
|
||||
|
||||
box-shadow: 0 0 60px 30px rgba(255, 240, 150, 0.15);
|
||||
}
|
||||
|
||||
@keyframes slideInOutSpotlight {
|
||||
0% {
|
||||
top: -800px;
|
||||
opacity: 0;
|
||||
}
|
||||
20% {
|
||||
top: -640px; /* Endposition */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: -640px;
|
||||
opacity: 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@keyframes fadeOutSpotlight {
|
||||
0% {
|
||||
top: -640px;
|
||||
opacity: 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
100% {
|
||||
top: -640px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% block extra_js %}
|
||||
{% if is_last_question %}
|
||||
|
||||
<script>
|
||||
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
|
||||
const animationDuration = 1500; // Dauer der Wachstumsanimation
|
||||
const waitTime=3000;
|
||||
const podiums = [
|
||||
|
||||
{ id: 'podium-2', delay: 2000 }, // immer vorheriges von Bedeutung
|
||||
{ id: 'podium-1', delay: 2000 },
|
||||
{ id: 'podium-0', delay: 0 },
|
||||
];
|
||||
|
||||
|
||||
let totalDelay = 0;
|
||||
|
||||
podiums.forEach(({ delay }) => {
|
||||
totalDelay += delay + waitTime;
|
||||
});
|
||||
const totalAnimationTime = totalDelay + animationDuration;
|
||||
setTimeout(() => {
|
||||
show_score();
|
||||
}, totalAnimationTime);
|
||||
|
||||
totalDelay = 0;
|
||||
|
||||
|
||||
|
||||
podiums.forEach(({ id, delay }) => {
|
||||
|
||||
const podium = document.getElementById(id);
|
||||
if (!podium) return;
|
||||
|
||||
const finalHeight = parseInt(podium.dataset.finalHeight) || 160;
|
||||
podium.style.transition = `height ${animationDuration}ms ease-in-out`;
|
||||
podium.style.height = '0px';
|
||||
|
||||
// Wachstum starten nach gesamter Wartezeit
|
||||
setTimeout(() => {
|
||||
podium.style.height = `${finalHeight}vh`;
|
||||
}, totalDelay);
|
||||
|
||||
// Name & Score anzeigen nach Balken-Animation
|
||||
setTimeout(() => {
|
||||
|
||||
if (id === 'podium-0') {
|
||||
let name = document.getElementById(`display_name-0`);
|
||||
let score = document.getElementById(`score-0`);
|
||||
let winnerText= document.getElementById(`winner-text`);
|
||||
|
||||
let thanks= document.getElementById(`thanks`);
|
||||
// 1. Lichtkegel anzeigen
|
||||
if (resultFirst) {
|
||||
resultFirst.classList.add('spotlight-wrapper');
|
||||
score.classList.add('opacity-0');
|
||||
name.classList.add('opacity-0');
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 2. Nach kurzer Wartezeit Name & Score anzeigen
|
||||
setTimeout(() => {
|
||||
|
||||
if (name) {
|
||||
name.classList.add('opacity-100', 'animate-bounce','spotlight-text'); // z. B. sichtbar + Effekt
|
||||
}
|
||||
|
||||
if (winnerText) {
|
||||
winnerText.classList.remove('hidden');
|
||||
}
|
||||
|
||||
if (thanks) {
|
||||
thanks.classList.remove('hidden');
|
||||
}
|
||||
|
||||
if (score) {
|
||||
score.classList.add('opacity-100'); // z. B. sichtbar + Effekt
|
||||
}
|
||||
triggerConfetti();
|
||||
|
||||
}, 2000);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
document.body.style.overflow = 'auto';
|
||||
return;
|
||||
}
|
||||
|
||||
const index = id.split('-')[1];
|
||||
const name = document.getElementById(`display_name-${index}`);
|
||||
const score = document.getElementById(`score-${index}`);
|
||||
|
||||
document.body.style.overflow = 'hidden';
|
||||
|
||||
if (name && id !== 'podium-0') setTimeout(() => {
|
||||
name.classList.add('opacity-100');
|
||||
name.classList.add('animate-bounce');
|
||||
|
||||
if (score) score.classList.add('opacity-100');
|
||||
}, waitTime);
|
||||
|
||||
}, totalDelay + animationDuration);
|
||||
|
||||
|
||||
totalDelay += delay + waitTime; // wichtig: aufsummieren
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
|
||||
// Hilfsfunktion für Pausen
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
|
||||
function triggerConfetti() {
|
||||
const end = Date.now() + 30 * 1000;
|
||||
(function frame() {
|
||||
confetti({ particleCount: 2, angle: 60, spread: 55, origin: { x: 0 } });
|
||||
confetti({ particleCount: 2, angle: 120, spread: 55, origin: { x: 1 } });
|
||||
if (Date.now() < end) requestAnimationFrame(frame);
|
||||
})();
|
||||
}
|
||||
|
||||
function show_score() {
|
||||
|
||||
let player_score=document.getElementById('player_score');
|
||||
player_score.classList.remove('hidden');
|
||||
info=document.getElementById('info');
|
||||
info.classList.add('hidden');
|
||||
resultText=document.getElementById('result-text');
|
||||
resultText.textContent="Dein Ergebnis";
|
||||
|
||||
|
||||
|
||||
const myName = "{{ my_participant.id|escapejs }}";
|
||||
const firstPlaceName = "{{ participants.0.id|escapejs }}";
|
||||
|
||||
if (myName === firstPlaceName) {
|
||||
let winnerText= document.getElementById(`winner-text`);
|
||||
winnerText.classList.remove('hidden');
|
||||
triggerConfetti();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
</script>
|
||||
{% endif %}
|
||||
{% include 'play/game/common_scripts.html' %}
|
||||
{% if is_host %}
|
||||
{% include 'play/game/sound.html' %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
|
||||
|
||||
<script>
|
||||
async function start() {
|
||||
|
||||
elements=document.getElementsByClassName("show-score");
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
const el = elements[i];
|
||||
|
||||
let counter=Number(el.getAttribute('data-score'))-Number(el.getAttribute('data-last-score'));
|
||||
let goal=Number(el.getAttribute('data-score'));
|
||||
let interval= setInterval(function(){
|
||||
el.innerHTML = counter + " Punkte";
|
||||
|
||||
|
||||
if(counter<=goal){
|
||||
el.innerHTML = counter + " Punkte";
|
||||
counter+=8;
|
||||
|
||||
}
|
||||
else{
|
||||
|
||||
el.innerHTML = goal + " Punkte";
|
||||
clearInterval(interval);
|
||||
}
|
||||
|
||||
}, 20);}}
|
||||
|
||||
function bounce(){
|
||||
|
||||
const names = document.getElementsByClassName("display_name");
|
||||
for (let i = 0; i < names.length; i++) {
|
||||
names[i].classList.add("animate-bounce");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{% if is_last_question %}
|
||||
start();
|
||||
bounce();
|
||||
|
||||
|
||||
{% else %}
|
||||
start();
|
||||
{% endif %}
|
||||
|
||||
const richtigeAntworten = [
|
||||
"Deine Antwort ist nicht falsch. Sie ist richtig!",
|
||||
"Ja, du kannst es!",
|
||||
"So kann es weiter gehen.",
|
||||
"Ja, deine Antwort ist korrekt. Was soll ich dazu noch sagen? SUPER!",
|
||||
"SUPER GUT.",
|
||||
"Volltreffer!",
|
||||
"Bravo! Das sitzt!",
|
||||
"Na bitte, geht doch!",
|
||||
"Schön. Einfach schön.",
|
||||
"Exzellent kombiniert, Sherlock!",
|
||||
"Punkt für dich!",
|
||||
"Das war meisterhaft.",
|
||||
"Korrekt - du scheinst das zu können!",
|
||||
"So sieht Erfolg aus!",
|
||||
"Glänzend gelöst!",
|
||||
"Das war keine Glückssache - das war Können!",
|
||||
"Treffer, versenkt!",
|
||||
"Du hast es drauf!",
|
||||
"Da merkt man: Profi am Werk.",
|
||||
"Richtige Antwort - dafür gibt es viele Punkte!",
|
||||
"Weiter so!",
|
||||
"Wow - das war richtig gut!"
|
||||
];
|
||||
|
||||
const falscheAntworten = [
|
||||
"Oops! War wohl nicht dein Tag.",
|
||||
"Knapp daneben ist auch vorbei!",
|
||||
"Das war... kreativ!",
|
||||
"Wenn man schon alles wüsste, wäre das Quiz doch sinnlos.",
|
||||
"Deine Antwort war einzigartig - leider falsch!",
|
||||
"Na gut, wenigstens hast du es probiert.",
|
||||
"Das war eine interessante Theorie...",
|
||||
"Ein Genie irrt sich auch mal.",
|
||||
"Eine gute Antwort - aber nicht auf diese Frage.",
|
||||
"Das ist leider falsch. Mehr gibt es nicht zu sagen.",
|
||||
"Gute Idee! Aber leider nicht richtig.",
|
||||
"Oh weh! Ein Fehler. Naja, einer ist keiner.",
|
||||
"Die Antwort klang richtig, sie ist es aber nicht.",
|
||||
"Interessanter Ansatz. Nicht hilfreich, aber interessant.",
|
||||
"Nenn das lieber „alternative Fakten“.",
|
||||
"Du hast die richtige Antwort doch gewusst: 'Die Seite hat nur nicht geladen.'",
|
||||
"Jeder fängt mal klein an!",
|
||||
"Kopf hoch - weiter geht's!",
|
||||
"Nobody is perfect!",
|
||||
"Du schaffst das - vielleicht ab jetzt.",
|
||||
"Falsche Antwort, aber guter Wille!",
|
||||
"Übung macht den Quiz-Meister.",
|
||||
"Beim nächsten Mal triffst du!",
|
||||
"Das war nur zum Aufwärmen, oder?",
|
||||
"Kein Problem - weiter geht's.",
|
||||
"Gute Frage - aber falsche Antwort."
|
||||
];
|
||||
|
||||
|
||||
const antwortRichtig = document.getElementById("antwort-richtig");
|
||||
const antwortFalsch = document.getElementById("antwort-falsch");
|
||||
|
||||
if (antwortRichtig) {
|
||||
antwortRichtig.textContent = richtigeAntworten[Math.floor(Math.random() * richtigeAntworten.length)];
|
||||
} else if (antwortFalsch) {
|
||||
antwortFalsch.textContent = falscheAntworten[Math.floor(Math.random() * falscheAntworten.length)];
|
||||
}
|
||||
const joinCode = '{{ quiz_game.join_code }}';
|
||||
const hostId = '{{ host_id }}';
|
||||
const wsScheme = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
||||
const gameSocket = new WebSocket(
|
||||
`${wsScheme}://${window.location.host}/ws/game/${joinCode}/`
|
||||
);
|
||||
|
||||
gameSocket.onmessage = function(e) {
|
||||
const data = JSON.parse(e.data);
|
||||
if (data.type === 'game_state_update' &&
|
||||
data.redirect_url &&
|
||||
(data.action === 'next_question' || data.action === 'finish_game' || data.action === 'show_winner_podest')) {
|
||||
window.location.href = data.redirect_url;
|
||||
}
|
||||
else if (data.type === 'answer_stats') {
|
||||
updateAnswerStats(data.stats);
|
||||
}
|
||||
};
|
||||
|
||||
gameSocket.onclose = function(e) {
|
||||
// Normal closure (code 1000) oder Navigation zu einer anderen Seite (code 1001)
|
||||
if (e.code === 1000 || e.code === 1001) {
|
||||
console.log('Game socket closed normally');
|
||||
} else {
|
||||
console.error('Game socket closed unexpectedly', e.code);
|
||||
}
|
||||
};
|
||||
|
||||
{% if is_host %}
|
||||
// Add click handlers for host buttons
|
||||
{% if is_last_question %}
|
||||
var finishButton = document.getElementById('finish-button');
|
||||
if (finishButton) {
|
||||
finishButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'finish_game',
|
||||
'host_id': hostId
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
var podestButton = document.getElementById('winner-button');
|
||||
if (podestButton) {
|
||||
podestButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'winner_podest',
|
||||
'host_id': hostId
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
{% else %}
|
||||
|
||||
var nextButton = document.getElementById('next-button');
|
||||
if (nextButton) {
|
||||
nextButton.addEventListener('click', function() {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'next_question',
|
||||
'host_id': hostId
|
||||
}));
|
||||
}, { once: true });
|
||||
}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
function updateAnswerStats(stats) {
|
||||
const total = Object.values(stats).reduce((a, b) => a + b, 0) || 1;
|
||||
|
||||
for (var optionIndex in stats) {
|
||||
if (stats.hasOwnProperty(optionIndex)) {
|
||||
var countElement = document.getElementById('option-count-' + optionIndex);
|
||||
var fillElement = document.getElementById('option-fill-' + optionIndex);
|
||||
|
||||
if (countElement) {
|
||||
countElement.textContent = stats[optionIndex] + ' Antwort(en)';
|
||||
}
|
||||
|
||||
if (fillElement) {
|
||||
const percentage = Math.round((stats[optionIndex] / total) * 100);
|
||||
fillElement.style.width = percentage + '%';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Request answer stats when page loads
|
||||
gameSocket.onopen = function(e) {
|
||||
gameSocket.send(JSON.stringify({
|
||||
'type': 'get_answer_stats'
|
||||
}));
|
||||
};
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
Reference in New Issue
Block a user