diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt index c4e1e10..32b2c5c 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/api/PlayerHandler.kt @@ -34,7 +34,18 @@ object PlayerHandler: PairgothApiHandler { val player = tournament.players[id] ?: badRequest("invalid player id") val payload = getObjectPayload(request) val updated = Player.fromJson(payload, player) - tournament.players[updated.id] = updated + // check coherence + if (player.final && !updated.final && tournament.pairedPlayers().contains(updated.id)) { + badRequest("player is playing") + } + val leavingRounds = updated.skip.toSet().minus(player.skip.toSet()) + leavingRounds.forEach { round -> + val playing = tournament.games(round).values.flatMap { listOf(it.black, it.white) } + if (playing.contains(id)) { + throw badRequest("player is playing in round #$round") + } + } + tournament.players[id] = updated tournament.dispatchEvent(PlayerUpdated, player.toJson()) return Json.Object("success" to true) } @@ -42,6 +53,11 @@ object PlayerHandler: PairgothApiHandler { override fun delete(request: HttpServletRequest, response: HttpServletResponse): Json { val tournament = getTournament(request) val id = getSubSelector(request)?.toIntOrNull() ?: badRequest("missing or invalid player selector") + // check coherence + val player = tournament.players[id] ?: badRequest("invalid player id") + if (player.final && tournament.pairedPlayers().contains(id)) { + badRequest("player is playing") + } tournament.players.remove(id) ?: badRequest("invalid player id") tournament.dispatchEvent(PlayerDeleted, Json.Object("id" to id)) return Json.Object("success" to true) diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt index adc7800..15a73e3 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Tournament.kt @@ -114,6 +114,8 @@ sealed class Tournament ( } return changed } + + fun pairedPlayers() = games.flatMap { it.values }.flatMap { listOf(it.black, it.white) }.toSet() } // standard tournament of individuals diff --git a/view-webapp/src/main/sass/main.scss b/view-webapp/src/main/sass/main.scss index 269f37f..f424aa4 100644 --- a/view-webapp/src/main/sass/main.scss +++ b/view-webapp/src/main/sass/main.scss @@ -434,9 +434,14 @@ } .toggle { - display: inline-block; + padding-top: 0.2em; + display: inline-flex; + flex-flow: column nowrap; + justify-content: space-evenly; + align-items: center; cursor: pointer; text-align: center; + vertical-align: middle; input { display: none !important; } diff --git a/view-webapp/src/main/sass/tour.scss b/view-webapp/src/main/sass/tour.scss index 57f2880..044fdf1 100644 --- a/view-webapp/src/main/sass/tour.scss +++ b/view-webapp/src/main/sass/tour.scss @@ -63,6 +63,9 @@ #players-list { max-width: 95vw; + #players tr.filtered { + display: none; + } } #player { diff --git a/view-webapp/src/main/webapp/js/main.js b/view-webapp/src/main/webapp/js/main.js index fb75ffc..0a4cad2 100644 --- a/view-webapp/src/main/webapp/js/main.js +++ b/view-webapp/src/main/webapp/js/main.js @@ -199,7 +199,7 @@ onLoad(() => { switch (e.key) { case 'Escape': { if (tab === '#registration') { - if ($('#player').hasClass('shown') && $('#needle')[0].value) { + if ($('#player').hasClass('shown') && searchResultShown()) { $('#needle')[0].value = ''; initSearch(); } else { diff --git a/view-webapp/src/main/webapp/js/tour-registration.inc.js b/view-webapp/src/main/webapp/js/tour-registration.inc.js index 968862b..54fe19d 100644 --- a/view-webapp/src/main/webapp/js/tour-registration.inc.js +++ b/view-webapp/src/main/webapp/js/tour-registration.inc.js @@ -260,7 +260,7 @@ onLoad(() => { } } } - $('.toggle').on('click', e => { + $('#search-form .toggle').on('click', e => { let chk = e.target.closest('.toggle'); let checkbox = chk.find('input')[0]; checkbox.checked = !checkbox.checked; @@ -269,6 +269,16 @@ onLoad(() => { store(id, value); initSearch(); }); + $('#list-header .toggle').on('click', e => { + let chk = e.target.closest('.toggle'); + let checkbox = chk.find('input')[0]; + checkbox.checked = !checkbox.checked; + if (checkbox.checked) { + $('td.reg-status:not(.final)').forEach(node => node.parentNode.addClass('filtered')); + } else { + $('td.reg-status:not(.final)').forEach(node => node.parentNode.removeClass('filtered')); + } + }); document.on('click', e => { let resultLine = e.target.closest('.result-line'); if (resultLine) { @@ -320,12 +330,12 @@ onLoad(() => { id: id, final: newStatus }).then(player => { - if (player !== 'error') { - cell.toggleClass('final'); - standingsUpToDate = false; - pairablesUpToDate = false; - } - }); + if (player !== 'error') { + cell.toggleClass('final'); + standingsUpToDate = false; + pairablesUpToDate = false; + } + }); e.preventDefault(); return false; }); diff --git a/view-webapp/src/main/webapp/tour-registration.inc.html b/view-webapp/src/main/webapp/tour-registration.inc.html index 1bad515..0d83d8a 100644 --- a/view-webapp/src/main/webapp/tour-registration.inc.html +++ b/view-webapp/src/main/webapp/tour-registration.inc.html @@ -3,9 +3,18 @@
-
- - +
+
+ + +
+
+ +
+
+
+ +
$parts.size() participants, $utils.countFinals($parts) confirmed.