2023-03-23 15:17:29 +00:00
|
|
|
(async () => {
|
|
|
|
// check notification permission
|
|
|
|
await Notification.requestPermission()
|
|
|
|
})()
|
|
|
|
|
2023-03-22 14:24:15 +00:00
|
|
|
const tournaments = JSON.parse(document.getElementById('tournaments_list').textContent)
|
|
|
|
const sockets = {}
|
|
|
|
|
2023-03-22 17:44:49 +00:00
|
|
|
const messages = document.getElementById('messages')
|
2023-03-22 14:24:15 +00:00
|
|
|
|
2023-03-23 15:17:29 +00:00
|
|
|
function drawDice(tid, trigram = null) {
|
|
|
|
sockets[tid].send(JSON.stringify({'type': 'dice', 'trigram': trigram}))
|
|
|
|
}
|
|
|
|
|
|
|
|
function showNotification(title, body, timeout = 5000) {
|
|
|
|
let notif = new Notification(title, {'body': body, 'icon': "/static/tfjm.svg"})
|
|
|
|
if (timeout)
|
|
|
|
setTimeout(() => notif.close(), timeout)
|
|
|
|
}
|
|
|
|
|
2023-03-22 17:44:49 +00:00
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
2023-03-22 19:41:16 +00:00
|
|
|
if (document.location.hash) {
|
|
|
|
document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(elem => {
|
|
|
|
if ('#' + elem.innerText.toLowerCase() === document.location.hash.toLowerCase()) {
|
|
|
|
elem.click()
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
document.querySelectorAll('button[data-bs-toggle="tab"]').forEach(
|
|
|
|
elem => elem.addEventListener(
|
|
|
|
'click', () => document.location.hash = '#' + elem.innerText.toLowerCase()))
|
|
|
|
|
2023-03-22 17:44:49 +00:00
|
|
|
for (let tournament of tournaments) {
|
|
|
|
let socket = new WebSocket(
|
2023-03-23 15:17:29 +00:00
|
|
|
(document.location.protocol === 'https:' ? 'wss' : 'ws') + '://' + window.location.host
|
|
|
|
+ '/ws/draw/' + tournament.id + '/'
|
2023-03-22 17:44:49 +00:00
|
|
|
)
|
|
|
|
sockets[tournament.id] = socket
|
|
|
|
|
|
|
|
function addMessage(message, type, timeout = 0) {
|
|
|
|
const wrapper = document.createElement('div')
|
|
|
|
wrapper.innerHTML = [
|
|
|
|
`<div class="alert alert-${type} alert-dismissible" role="alert">`,
|
|
|
|
`<div>${message}</div>`,
|
|
|
|
'<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>',
|
|
|
|
].join('\n')
|
|
|
|
messages.append(wrapper)
|
2023-03-22 14:24:15 +00:00
|
|
|
|
2023-03-22 17:44:49 +00:00
|
|
|
if (timeout)
|
|
|
|
setTimeout(() => wrapper.remove(), timeout)
|
2023-03-22 14:24:15 +00:00
|
|
|
}
|
2023-03-22 17:44:49 +00:00
|
|
|
|
2023-03-23 15:17:29 +00:00
|
|
|
function setInfo(info) {
|
|
|
|
document.getElementById(`messages-${tournament.id}`).innerHTML = info
|
|
|
|
}
|
|
|
|
|
|
|
|
function drawStart() {
|
2023-03-22 19:41:16 +00:00
|
|
|
document.getElementById(`banner-not-started-${tournament.id}`).classList.add('d-none')
|
|
|
|
document.getElementById(`draw-content-${tournament.id}`).classList.remove('d-none')
|
2023-03-22 17:44:49 +00:00
|
|
|
}
|
|
|
|
|
2023-03-23 15:17:29 +00:00
|
|
|
function updateDiceInfo(trigram, result) {
|
|
|
|
let elem = document.getElementById(`dice-${tournament.id}-${trigram}`)
|
|
|
|
if (result === null) {
|
|
|
|
elem.classList.remove('text-bg-success')
|
|
|
|
elem.classList.add('text-bg-warning')
|
|
|
|
elem.innerText = `${trigram} 🎲 ??`
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
elem.classList.remove('text-bg-warning')
|
|
|
|
elem.classList.add('text-bg-success')
|
|
|
|
elem.innerText = `${trigram} 🎲 ${result}`
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateDiceVisibility(visible) {
|
|
|
|
let div = document.getElementById(`launch-dice-${tournament.id}`)
|
|
|
|
if (visible)
|
|
|
|
div.classList.remove('d-none')
|
|
|
|
else
|
|
|
|
div.classList.add('d-none')
|
|
|
|
}
|
|
|
|
|
2023-03-24 10:10:07 +00:00
|
|
|
function updatePoules(round, poules) {
|
|
|
|
let roundList = document.getElementById(`recap-${tournament.id}-round-list`)
|
|
|
|
let poolListId = `recap-${tournament.id}-round-${round}-pool-list`
|
|
|
|
let poolList = document.getElementById(poolListId)
|
|
|
|
if (poolList === null) {
|
|
|
|
let li = document.createElement('li')
|
|
|
|
li.id = `recap-${tournament.id}-round-${round}`
|
|
|
|
li.classList.add('list-group-item')
|
|
|
|
li.setAttribute('data-tournament', tournament.id)
|
|
|
|
|
|
|
|
let title = document.createElement('strong')
|
|
|
|
title.textContent = 'Tour ' + round
|
|
|
|
|
|
|
|
poolList = document.createElement('ul')
|
|
|
|
poolList.id = poolListId
|
|
|
|
poolList.classList.add('list-group', 'list-group-flush')
|
|
|
|
|
|
|
|
li.append(title, poolList)
|
|
|
|
roundList.append(li)
|
|
|
|
}
|
|
|
|
|
|
|
|
let c = 1
|
|
|
|
|
|
|
|
for (let poule of poules) {
|
|
|
|
let teamListId = `recap-${tournament.id}-round-${round}-pool-${poule.letter}-team-list`
|
|
|
|
let teamList = document.getElementById(teamListId)
|
|
|
|
if (teamList === null) {
|
|
|
|
let li = document.createElement('li')
|
|
|
|
li.id = `recap-${tournament.id}-round-${round}-pool-${poule.letter}`
|
|
|
|
li.classList.add('list-group-item')
|
|
|
|
li.setAttribute('data-tournament', tournament.id)
|
|
|
|
|
|
|
|
let title = document.createElement('strong')
|
|
|
|
title.textContent = 'Poule ' + poule.letter + round
|
|
|
|
|
|
|
|
teamList = document.createElement('ul')
|
|
|
|
teamList.id = teamListId
|
|
|
|
teamList.classList.add('list-group', 'list-group-flush')
|
|
|
|
|
|
|
|
li.append(title, teamList)
|
|
|
|
poolList.append(li)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (poule.teams.length > 0) {
|
|
|
|
for (let team of poule.teams) {
|
|
|
|
// Reorder dices
|
|
|
|
let diceDiv = document.getElementById(`dice-${tournament.id}-${team}`)
|
|
|
|
diceDiv.parentElement.style.order = c.toString()
|
|
|
|
c += 1
|
|
|
|
|
|
|
|
let teamLiId = `recap-team-${team}`
|
|
|
|
let teamLi = document.getElementById(teamLiId)
|
|
|
|
|
|
|
|
if (teamLi === null) {
|
|
|
|
teamLi = document.createElement('li')
|
|
|
|
teamLi.id = teamLiId
|
|
|
|
teamLi.classList.add('list-group-item')
|
|
|
|
teamLi.setAttribute('data-tournament', tournament.id)
|
|
|
|
|
|
|
|
teamList.append(teamLi)
|
|
|
|
}
|
|
|
|
|
|
|
|
let acceptedDivId = `recap-team-${team}-accepted`
|
|
|
|
let acceptedDiv = document.getElementById(acceptedDivId)
|
|
|
|
if (acceptedDiv === null) {
|
|
|
|
acceptedDiv = document.createElement('div')
|
|
|
|
acceptedDiv.id = acceptedDivId
|
|
|
|
acceptedDiv.classList.add('badge', 'rounded-pill', 'text-bg-warning')
|
|
|
|
acceptedDiv.textContent = `${team} 📃 ?`
|
|
|
|
teamLi.append(acceptedDiv)
|
|
|
|
}
|
|
|
|
|
|
|
|
let rejectedDivId = `recap-team-${team}-rejected`
|
|
|
|
let rejectedDiv = document.getElementById(rejectedDivId)
|
|
|
|
if (rejectedDiv === null) {
|
|
|
|
rejectedDiv = document.createElement('div')
|
|
|
|
rejectedDiv.id = rejectedDivId
|
|
|
|
rejectedDiv.classList.add('badge', 'rounded-pill', 'text-bg-danger')
|
|
|
|
rejectedDiv.textContent = '🗑️'
|
|
|
|
teamLi.append(rejectedDiv)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw tables
|
|
|
|
let tablesDiv = document.getElementById(`tables-${tournament.id}`)
|
|
|
|
let tablesRoundDiv = document.getElementById(`tables-${tournament.id}-round-${round}`)
|
|
|
|
if (tablesRoundDiv === null) {
|
|
|
|
let card = document.createElement('div')
|
|
|
|
card.classList.add('card', 'col-md-6')
|
|
|
|
tablesDiv.append(card)
|
|
|
|
|
|
|
|
let cardHeader = document.createElement('div')
|
|
|
|
cardHeader.classList.add('card-header')
|
|
|
|
cardHeader.innerHTML = `<h2>Tour ${round}</h2>`
|
|
|
|
card.append(cardHeader)
|
|
|
|
|
|
|
|
tablesRoundDiv = document.createElement('div')
|
|
|
|
tablesRoundDiv.id = `tables-${tournament.id}-round-${round}`
|
|
|
|
tablesRoundDiv.classList.add('card-body')
|
|
|
|
card.append(tablesRoundDiv)
|
|
|
|
}
|
|
|
|
|
|
|
|
for (let poule of poules) {
|
|
|
|
let pouleTable = document.getElementById(`table-${tournament.id}-${round}-${poule.letter}`)
|
|
|
|
if (pouleTable === null) {
|
|
|
|
// Create table
|
|
|
|
let card = document.createElement('div')
|
|
|
|
card.classList.add('card')
|
|
|
|
tablesRoundDiv.append(card)
|
|
|
|
|
|
|
|
let cardHeader = document.createElement('div')
|
|
|
|
cardHeader.classList.add('card-header')
|
|
|
|
cardHeader.innerHTML = `<h2>Poule ${poule.letter}</h2>`
|
|
|
|
card.append(cardHeader)
|
|
|
|
|
|
|
|
let cardBody = document.createElement('div')
|
|
|
|
cardBody.classList.add('card-body')
|
|
|
|
card.append(cardBody)
|
|
|
|
|
|
|
|
pouleTable = document.createElement('table')
|
|
|
|
pouleTable.id = `table-${tournament.id}-${round}-${poule.letter}`
|
|
|
|
pouleTable.classList.add('table', 'table-stripped')
|
|
|
|
cardBody.append(pouleTable)
|
|
|
|
|
|
|
|
let thead = document.createElement('thead')
|
|
|
|
pouleTable.append(thead)
|
|
|
|
|
|
|
|
let phaseTr = document.createElement('tr')
|
|
|
|
thead.append(phaseTr)
|
|
|
|
|
|
|
|
let teamTh = document.createElement('th')
|
|
|
|
teamTh.classList.add('text-center')
|
|
|
|
teamTh.rowSpan = poule.teams.length === 5 ? 3 : 2
|
|
|
|
teamTh.textContent = "Équipe"
|
|
|
|
phaseTr.append(teamTh)
|
|
|
|
|
|
|
|
for (let i = 1; i <= 3; ++i) {
|
|
|
|
let phaseTh = document.createElement('th')
|
|
|
|
phaseTh.classList.add('text-center')
|
|
|
|
if (poule.teams.length === 5 && i < 3)
|
|
|
|
phaseTh.colSpan = 2
|
|
|
|
phaseTh.textContent = `Phase ${i}`
|
|
|
|
phaseTr.append(phaseTh)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (poule.teams.length === 5) {
|
|
|
|
let roomTr = document.createElement('tr')
|
|
|
|
thead.append(roomTr)
|
|
|
|
|
|
|
|
for (let i = 0; i < 5; ++i) {
|
|
|
|
let roomTh = document.createElement('th')
|
|
|
|
roomTh.classList.add('text-center')
|
|
|
|
roomTh.textContent = `Salle ${1 + (i % 2)}`
|
|
|
|
roomTr.append(roomTh)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let problemTr = document.createElement('tr')
|
|
|
|
thead.append(problemTr)
|
|
|
|
|
|
|
|
for (let team of poule.teams) {
|
|
|
|
let problemTh = document.createElement('th')
|
|
|
|
problemTh.classList.add('text-center')
|
|
|
|
problemTh.innerHTML = `Problème <span id="table-${tournament.id}-round-${round}-problem-${team}">?</span>`
|
|
|
|
problemTr.append(problemTh)
|
|
|
|
}
|
|
|
|
|
|
|
|
let tbody = document.createElement('tbody')
|
|
|
|
pouleTable.append(tbody)
|
|
|
|
|
|
|
|
for (let i = 0; i < poule.teams.length; ++i) {
|
|
|
|
let team = poule.teams[i]
|
|
|
|
|
|
|
|
let teamTr = document.createElement('tr')
|
|
|
|
tbody.append(teamTr)
|
|
|
|
|
|
|
|
let teamTd = document.createElement('td')
|
|
|
|
teamTd.classList.add('text-center')
|
|
|
|
teamTd.innerText = team
|
|
|
|
teamTr.append(teamTd)
|
|
|
|
|
|
|
|
let defenderTd = document.createElement('td')
|
|
|
|
defenderTd.classList.add('text-center')
|
|
|
|
defenderTd.innerText = 'Défenseur⋅se'
|
|
|
|
|
|
|
|
let opponentTd = document.createElement('td')
|
|
|
|
opponentTd.classList.add('text-center')
|
|
|
|
opponentTd.innerText = 'Opposant⋅e'
|
|
|
|
|
|
|
|
let reporterTd = document.createElement('td')
|
|
|
|
reporterTd.classList.add('text-center')
|
|
|
|
reporterTd.innerText = 'Rapporteur⋅e'
|
|
|
|
|
|
|
|
let emptyTd = document.createElement('td')
|
|
|
|
|
|
|
|
|
|
|
|
if (poule.teams.length === 3) {
|
|
|
|
switch (i) {
|
|
|
|
case 0:
|
|
|
|
teamTr.append(defenderTd, reporterTd, opponentTd)
|
|
|
|
break
|
|
|
|
case 1:
|
|
|
|
teamTr.append(opponentTd, defenderTd, reporterTd)
|
|
|
|
break
|
|
|
|
case 2:
|
|
|
|
teamTr.append(reporterTd, opponentTd, defenderTd)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (poule.teams.length === 4) {
|
|
|
|
switch (i) {
|
|
|
|
case 0:
|
|
|
|
teamTr.append(defenderTd, emptyTd, reporterTd, opponentTd)
|
|
|
|
break
|
|
|
|
case 1:
|
|
|
|
teamTr.append(opponentTd, defenderTd, emptyTd, reporterTd)
|
|
|
|
break
|
|
|
|
case 2:
|
|
|
|
teamTr.append(reporterTd, opponentTd, defenderTd, emptyTd)
|
|
|
|
break
|
|
|
|
case 3:
|
|
|
|
teamTr.append(emptyTd, reporterTd, opponentTd, defenderTd)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (poule.teams.length === 5) {
|
|
|
|
switch (i) {
|
|
|
|
case 0:
|
|
|
|
teamTr.append(defenderTd, emptyTd, opponentTd, reporterTd, emptyTd)
|
|
|
|
break
|
|
|
|
case 1:
|
|
|
|
teamTr.append(emptyTd, defenderTd, reporterTd, emptyTd, opponentTd)
|
|
|
|
break
|
|
|
|
case 2:
|
|
|
|
teamTr.append(opponentTd, emptyTd, defenderTd, emptyTd, reporterTd)
|
|
|
|
break
|
|
|
|
case 3:
|
|
|
|
teamTr.append(reporterTd, opponentTd, emptyTd, defenderTd, emptyTd)
|
|
|
|
break
|
|
|
|
case 4:
|
|
|
|
teamTr.append(emptyTd, reporterTd, emptyTd, opponentTd, defenderTd)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function updateActiveRecap(round, pool, team) {
|
|
|
|
document.querySelectorAll(`li.list-group-item-primary[data-tournament="${tournament.id}"]`)
|
|
|
|
.forEach(elem => elem.classList.remove('list-group-item-primary'))
|
|
|
|
document.querySelectorAll(`li.list-group-item-success[data-tournament="${tournament.id}"]`)
|
|
|
|
.forEach(elem => elem.classList.remove('list-group-item-success'))
|
|
|
|
document.querySelectorAll(`li.list-group-item-info[data-tournament="${tournament.id}"]`)
|
|
|
|
.forEach(elem => elem.classList.remove('list-group-item-info'))
|
|
|
|
|
|
|
|
let roundLi = document.getElementById(`recap-${tournament.id}-round-${round}`)
|
|
|
|
if (roundLi !== null)
|
|
|
|
roundLi.classList.add('list-group-item-primary')
|
|
|
|
|
|
|
|
let poolLi = document.getElementById(`recap-${tournament.id}-round-${round}-pool-${pool}`)
|
|
|
|
if (poolLi !== null)
|
|
|
|
poolLi.classList.add('list-group-item-success')
|
|
|
|
|
|
|
|
let teamLi = document.getElementById(`recap-team-${team}`)
|
|
|
|
if (teamLi !== null)
|
|
|
|
teamLi.classList.add('list-group-item-info')
|
|
|
|
}
|
|
|
|
|
2023-03-22 17:44:49 +00:00
|
|
|
socket.addEventListener('message', e => {
|
|
|
|
const data = JSON.parse(e.data)
|
|
|
|
console.log(data)
|
|
|
|
|
|
|
|
switch (data.type) {
|
|
|
|
case 'alert':
|
|
|
|
addMessage(data.message, data.alert_type)
|
|
|
|
break
|
2023-03-23 15:17:29 +00:00
|
|
|
case 'notification':
|
|
|
|
showNotification(data.title, data.body)
|
2023-03-24 10:10:07 +00:00
|
|
|
break
|
2023-03-23 15:17:29 +00:00
|
|
|
case 'set_info':
|
|
|
|
setInfo(data.information)
|
|
|
|
break
|
2023-03-22 17:44:49 +00:00
|
|
|
case 'draw_start':
|
2023-03-23 15:17:29 +00:00
|
|
|
drawStart()
|
|
|
|
break
|
|
|
|
case 'dice':
|
|
|
|
updateDiceInfo(data.team, data.result)
|
|
|
|
break
|
|
|
|
case 'dice_visibility':
|
|
|
|
updateDiceVisibility(data.visible)
|
|
|
|
break
|
2023-03-24 10:10:07 +00:00
|
|
|
case 'set_poules':
|
|
|
|
updatePoules(data.round, data.poules)
|
|
|
|
break
|
|
|
|
case 'set_active':
|
|
|
|
updateActiveRecap(data.round, data.poule, data.team)
|
|
|
|
break
|
2023-03-22 17:44:49 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
socket.addEventListener('close', e => {
|
|
|
|
console.error('Chat socket closed unexpectedly')
|
|
|
|
})
|
|
|
|
|
|
|
|
socket.addEventListener('open', e => {})
|
|
|
|
|
2023-03-23 15:17:29 +00:00
|
|
|
let format_form = document.getElementById('format-form-' + tournament.id)
|
|
|
|
if (format_form !== null) {
|
|
|
|
format_form.addEventListener('submit', function (e) {
|
|
|
|
e.preventDefault()
|
2023-03-22 17:44:49 +00:00
|
|
|
|
2023-03-23 15:17:29 +00:00
|
|
|
socket.send(JSON.stringify({
|
|
|
|
'type': 'start_draw',
|
|
|
|
'fmt': document.getElementById('format-' + tournament.id).value
|
|
|
|
}))
|
|
|
|
})
|
|
|
|
}
|
2023-03-22 17:44:49 +00:00
|
|
|
}
|
|
|
|
})
|