158 lines
5.1 KiB
HTML
158 lines
5.1 KiB
HTML
<!-- host.html -->
|
|
{% extends 'base.html' %}
|
|
{% block content %}
|
|
<h1 class="mb-4">Public Quiz</h1>
|
|
<div class="container" id="host-app">
|
|
<!-- QR & Join Roster -->
|
|
<div id="qrContainer" class="mb-4 text-center">
|
|
<img id="qrImg"
|
|
src="data:image/png;base64,{{ qr_data }}"
|
|
class="img-fluid"
|
|
style="max-width:300px;"/>
|
|
</div>
|
|
|
|
<!-- new-game form -->
|
|
<form action="{{ url_for('new_game') }}" method="post" class="d-inline">
|
|
<button type="submit" class="btn btn-secondary mb-3" id="newGameButton">
|
|
Spiel neu starten
|
|
</button>
|
|
</form>
|
|
|
|
<button id="startBtn" class="btn btn-primary mb-3" disabled>Spiel beginnen</button>
|
|
<h3 id="rosterHeader">Spieler Beigetreten:</h3>
|
|
<ul id="roster" class="list-group mb-4"></ul>
|
|
|
|
<!-- Question & Current Leaderboard -->
|
|
<div id="host-question" style="display:none;">
|
|
<h2 id="qText" style="font-size:5rem;"></h2>
|
|
<div id="host-results" style="display:none; margin:20px;">
|
|
<ul id="perQ" class="list-group mb-3 text-center"></ul>
|
|
</div>
|
|
<div class="mt-3">
|
|
<button id="showAnswerBtn" class="btn btn-info">Antwort zeigen</button>
|
|
<button id="nextBtn" class="btn btn-warning" disabled>Nächste Frage</button>
|
|
</div>
|
|
</div>
|
|
|
|
|
|
<!-- Final Top-10 Leaderboard -->
|
|
<div id="final-results" style="display:none;" class="mt-4">
|
|
<h4>Rangliste</h4>
|
|
<table class="table table-striped">
|
|
<thead>
|
|
<tr><th>Rang</th><th>Name</th><th>Punkte</th></tr>
|
|
</thead>
|
|
<tbody id="finalResultsBody"></tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Persistent Overall Leaderboard Footer -->
|
|
<footer id="overallFooter" class="mt-4 bg-light border-top" style="position:fixed; bottom:0; left:0; width:100%; z-index:1000; display:none;">
|
|
<div class="container py-2">
|
|
<h4 class="mb-2">Rangliste</h4>
|
|
<table class="table table-striped mb-0">
|
|
<thead><tr><th>Name</th><th>Punkte</th></tr></thead>
|
|
<tbody id="overallFooterBody"></tbody>
|
|
</table>
|
|
</div>
|
|
</footer>
|
|
</div>
|
|
|
|
<script>
|
|
const socket = io();
|
|
|
|
// Connect and fetch roster
|
|
socket.on('connect', () => {
|
|
console.log('Connected as host');
|
|
socket.emit('get_roster');
|
|
});
|
|
|
|
// Update roster when players join
|
|
socket.on('update_roster', data => {
|
|
console.log('Roster update:', data.players);
|
|
$('#roster').empty();
|
|
data.players.forEach(name => {
|
|
$('#roster').append(`<li class="list-group-item">${name}</li>`);
|
|
});
|
|
$('#startBtn').prop('disabled', data.players.length === 0);
|
|
});
|
|
|
|
// Start game
|
|
$('#startBtn').on('click', () => {
|
|
console.log('Start game clicked');
|
|
$('#newGameButton').hide();
|
|
$('#overallFooter').show();
|
|
socket.emit('start_game');
|
|
});
|
|
|
|
// Handle new question
|
|
socket.on('new_question', data => {
|
|
console.log('New question:', data.question);
|
|
$('#qrContainer, #startBtn, #rosterHeader, #roster').hide();
|
|
$('#host-question').show();
|
|
$('#qText').text(data.question);
|
|
$('#host-results').hide();
|
|
$('#showAnswerBtn').prop({ disabled: false }).show();
|
|
$('#nextBtn').prop('disabled', true);
|
|
});
|
|
|
|
// Overall leaderboard updates (max 5 rows)
|
|
socket.on('overall_leader', data => {
|
|
console.log('Overall leader:', data.board);
|
|
window.lastOverall = data;
|
|
$('#overallFooterBody').empty();
|
|
const top5 = data.board.slice(0, 5);
|
|
top5.forEach(p => {
|
|
$('#overallFooterBody').append(`<tr><td>${p.name}</td><td>${p.score}</td></tr>`);
|
|
});
|
|
});
|
|
|
|
// Next question
|
|
$('#nextBtn').off('click').on('click', () => {
|
|
console.log('Next question clicked');
|
|
socket.emit('next_question');
|
|
});
|
|
|
|
// when host clicks “Show Answer”
|
|
$('#showAnswerBtn').off('click').on('click', () => {
|
|
socket.emit('show_answer');
|
|
});
|
|
|
|
// once server confirms the answer is revealed
|
|
socket.on('answer_revealed', data => {
|
|
// display the correct answer on host screen
|
|
$('#perQ').empty();
|
|
$('#perQ').append(
|
|
`<li class="list-group-item list-group-item-success" style="font-size:5rem;">${data.correct}</li>`
|
|
);
|
|
$('#host-results').show();
|
|
|
|
// disable Show Answer button, enable Next
|
|
$('#showAnswerBtn').prop('disabled', true);
|
|
$('#nextBtn').prop('disabled', false);
|
|
});
|
|
|
|
// Show final top-10 when game_over arrives
|
|
socket.on('game_over', data => {
|
|
if (data.board) {
|
|
// hide all the old UI
|
|
$('#qrContainer, #startBtn, #rosterHeader, #roster, #host-question, #host-results, #overallFooter').hide();
|
|
$('#newGameButton').show();
|
|
|
|
// fill & show your existing <div id="final-results">…
|
|
const top10 = data.board.slice(0, 10);
|
|
$('#finalResultsBody').empty();
|
|
top10.forEach((p, i) => {
|
|
$('#finalResultsBody').append(
|
|
`<tr><td>${i+1}</td><td>${p.name}</td><td>${p.score}</td></tr>`
|
|
);
|
|
});
|
|
$('#final-results').show();
|
|
|
|
// make absolutely sure the “Start Game” button stays disabled
|
|
$('#startBtn').prop('disabled', true);
|
|
}
|
|
});
|
|
</script>
|
|
{% endblock %}
|