(async () => { // check notification permission // This is useful to alert people that they should do something await Notification.requestPermission() })() const TFJM = JSON.parse(document.getElementById('TFJM_settings').textContent) const RECOMMENDED_SOLUTIONS_COUNT = TFJM.RECOMMENDED_SOLUTIONS_COUNT const problems_count = JSON.parse(document.getElementById('problems_count').textContent) const tournaments = JSON.parse(document.getElementById('tournaments_list').textContent) let socket = null const messages = document.getElementById('messages') /** * Request to abort the draw of the given tournament. * Only volunteers are allowed to do this. * @param tid The tournament id */ function abortDraw(tid) { socket.send(JSON.stringify({'tid': tid, 'type': 'abort'})) } /** * Request to cancel the last step. * Only volunteers are allowed to do this. * @param tid The tournament id */ function cancelLastStep(tid) { socket.send(JSON.stringify({'tid': tid, 'type': 'cancel'})) } /** * Request to launch a dice between 1 and 100, for the two first steps. * The parameter `trigram` can be specified (by volunteers) to launch a dice for a specific team. * @param tid The tournament id * @param trigram The trigram of the team that a volunteer wants to force the dice launch (default: null) * @param result The forced value. Null if unused (for regular people) */ function drawDice(tid, trigram = null, result = null) { socket.send(JSON.stringify({'tid': tid, 'type': 'dice', 'trigram': trigram, 'result': result})) } /** * Fetch the requested dice from the buttons and request to draw it. * Only available for debug purposes and for admins. * @param tid The tournament id */ function drawDebugDice(tid) { let dice_10 = parseInt(document.querySelector(`input[name="debug-dice-${tid}-10"]:checked`).value) let dice_1 = parseInt(document.querySelector(`input[name="debug-dice-${tid}-1"]:checked`).value) let result = (dice_10 + dice_1) || 100 let team_div = document.querySelector(`div[id="dices-${tid}"] > div > div[class*="text-bg-warning"]`) let team = team_div.getAttribute("data-team") drawDice(tid, team, result) } /** * Request to draw a new problem. * @param tid The tournament id * @param problem The forced problem. Null if unused (for regular people) */ function drawProblem(tid, problem = null) { socket.send(JSON.stringify({'tid': tid, 'type': 'draw_problem', 'problem': problem})) } /** * Accept the current proposed problem. * @param tid The tournament id */ function acceptProblem(tid) { socket.send(JSON.stringify({'tid': tid, 'type': 'accept'})) } /** * Reject the current proposed problem. * @param tid The tournament id */ function rejectProblem(tid) { socket.send(JSON.stringify({'tid': tid, 'type': 'reject'})) } /** * Volunteers can export the draw to make it available for notation. * @param tid The tournament id */ function exportDraw(tid) { socket.send(JSON.stringify({'tid': tid, 'type': 'export'})) } /** * Volunteers can make the draw continue for the second round of the final. * @param tid The tournament id */ function continueFinal(tid) { socket.send(JSON.stringify({'tid': tid, 'type': 'continue_final'})) } /** * Display a new notification with the given title and the given body. * @param title The title of the notification * @param body The body of the notification * @param timeout The time (in milliseconds) after that the notification automatically closes. 0 to make indefinite. Default to 5000 ms. * @return Notification */ function showNotification(title, body, timeout = 5000) { let notif = new Notification(title, {'body': body, 'icon': "/static/tfjm.svg"}) if (timeout) setTimeout(() => notif.close(), timeout) return notif } document.addEventListener('DOMContentLoaded', () => { if (document.location.hash) { // Open the tab of the tournament that is present in the hash document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(elem => { if ('#' + elem.innerText.toLowerCase() === document.location.hash.toLowerCase()) { elem.click() } }) } // When a tab is opened, add the tournament name in the hash document.querySelectorAll('button[data-bs-toggle="tab"]').forEach( elem => elem.addEventListener( 'click', () => document.location.hash = '#' + elem.innerText.toLowerCase())) /** * Add alert message on the top on the interface. * @param message The content of the alert. * @param type The alert type, which is a bootstrap color (success, info, warning, danger,…). * @param timeout The time (in milliseconds) before the alert is auto-closing. 0 to infinitely, default to 5000 ms. */ function addMessage(message, type, timeout = 5000) { const wrapper = document.createElement('div') wrapper.innerHTML = [ `