diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/ext/OpenGotha.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/ext/OpenGotha.kt index cd74f6e..35fc196 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/ext/OpenGotha.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/ext/OpenGotha.kt @@ -145,7 +145,8 @@ object OpenGotha { rating = player.rating, rank = Pairable.parseRank(player.rank), country = player.country, - club = player.club + club = player.club, + final = "FIN" == player.registeringStatus ).also { player.participating.toString().forEachIndexed { i,c -> if (c == '0') it.skip.add(i + 1) @@ -215,7 +216,9 @@ object OpenGotha { player.displayRank() }" rating="${ player.rating - }" ratingOrigin="" registeringStatus="FIN" smmsCorrection="0"/>""" + }" ratingOrigin="" registeringStatus="${ + if (player.final) "FIN" else "PRE" + }" smmsCorrection="0"/>""" } } diff --git a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairable.kt b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairable.kt index b13c502..068c681 100644 --- a/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairable.kt +++ b/api-webapp/src/main/kotlin/org/jeudego/pairgoth/model/Pairable.kt @@ -7,10 +7,10 @@ import java.util.* // Pairable -sealed class Pairable(val id: ID, val name: String, open val rating: Int, open val rank: Int) { +sealed class Pairable(val id: ID, val name: String, open val rating: Int, open val rank: Int, val final: Boolean) { companion object { - val MIN_RANK: Int = -30 // 30k - val MAX_RANK: Int = 8 // 9D + const val MIN_RANK: Int = -30 // 30k + const val MAX_RANK: Int = 8 // 9D } abstract fun toJson(): Json.Object abstract fun toMutableJson(): Json.MutableObject @@ -26,7 +26,7 @@ sealed class Pairable(val id: ID, val name: String, open val rating: Int, open v } } -object ByePlayer: Pairable(0, "bye", 0, Int.MIN_VALUE) { +object ByePlayer: Pairable(0, "bye", 0, Int.MIN_VALUE, true) { override fun toJson(): Json.Object { throw Error("bye player should never be serialized") } @@ -70,8 +70,9 @@ class Player( rating: Int, rank: Int, override var country: String, - override var club: String -): Pairable(id, name, rating, rank) { + override var club: String, + final: Boolean +): Pairable(id, name, rating, rank, final) { companion object // used to store external IDs ("FFG" => FFG ID, "EGF" => EGF PIN, "AGA" => AGA ID ...) val externalIds = mutableMapOf() @@ -82,7 +83,8 @@ class Player( "rating" to rating, "rank" to rank, "country" to country, - "club" to club + "club" to club, + "final" to final ).also { json -> if (skip.isNotEmpty()) json["skip"] = Json.Array(skip) externalIds.forEach { (dbid, id) -> @@ -103,7 +105,8 @@ fun Player.Companion.fromJson(json: Json.Object, default: Player? = null) = Play rating = json.getInt("rating") ?: default?.rating ?: badRequest("missing rating"), rank = json.getInt("rank") ?: default?.rank ?: badRequest("missing rank"), country = json.getString("country") ?: default?.country ?: badRequest("missing country"), - club = json.getString("club") ?: default?.club ?: badRequest("missing club") + club = json.getString("club") ?: default?.club ?: badRequest("missing club"), + final = json.getBoolean("final") ?: default?.final ?: true ).also { player -> player.skip.clear() json.getArray("skip")?.let { 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 d610218..fc2e116 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 @@ -128,7 +128,7 @@ class TeamTournament( override val players = mutableMapOf() val teams: MutableMap = _pairables - inner class Team(id: ID, name: String): Pairable(id, name, 0, 0) { + inner class Team(id: ID, name: String, final: Boolean): Pairable(id, name, 0, 0, final) { val playerIds = mutableSetOf() val teamPlayers: Set get() = playerIds.mapNotNull { players[id] }.toSet() override val rating: Int get() = if (teamPlayers.isEmpty()) super.rating else (teamPlayers.sumOf { player -> player.rating.toDouble() } / players.size).roundToInt() @@ -146,7 +146,8 @@ class TeamTournament( fun teamFromJson(json: Json.Object, default: TeamTournament.Team? = null) = Team( id = json.getInt("id") ?: default?.id ?: Store.nextPlayerId, - name = json.getString("name") ?: default?.name ?: badRequest("missing name") + name = json.getString("name") ?: default?.name ?: badRequest("missing name"), + final = json.getBoolean("final") ?: default?.final ?: badRequest("missing final") ).apply { json.getArray("players")?.let { arr -> arr.mapTo(playerIds) { diff --git a/view-webapp/src/main/sass/tour.scss b/view-webapp/src/main/sass/tour.scss index 0c565f1..590ba9c 100644 --- a/view-webapp/src/main/sass/tour.scss +++ b/view-webapp/src/main/sass/tour.scss @@ -143,6 +143,35 @@ #player.popup { min-width: 65vw; + #final-reg { + .final { + color: green; + display: none; + } + &.final { + .preliminary { + display: none; + } + .final { + display: initial; + } + } + } + } + + td.reg-status { + .final { + color: green; + display: none; + } + &.final { + .final { + display: initial; + } + .preliminary { + display: none; + } + } } /* pairing section */ 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 e2f6a4c..ed562e1 100644 --- a/view-webapp/src/main/webapp/js/tour-registration.inc.js +++ b/view-webapp/src/main/webapp/js/tour-registration.inc.js @@ -67,13 +67,17 @@ function parseRank(rank) { } function fillPlayer(player) { + // hack UK / GB + let country = player.country.toLowerCase(); + if ('uk' === country) country = 'gb'; let form = $('#player-form')[0]; form.val('name', player.name); form.val('firstname', player.firstname); - form.val('country', player.country.toLowerCase()); + form.val('country', country); form.val('club', player.club); form.val('rank', parseRank(player.rank)); form.val('rating', player.rating); + form.val('final', false); $('#needle')[0].value = ''; initSearch(); $('#register').focus(); @@ -90,8 +94,10 @@ onLoad(() => { $('#add').on('click', e => { let form = $('#player-form')[0]; form.addClass('add'); - // $('#player-form input.participation').forEach(chk => chk.checked = true); + // keep preliminary/final status + let status = form.val('final') || false; form.reset(); + form.val('final', status); $('#player').removeClass('edit').addClass('create'); modal('player'); $('#needle').focus(); @@ -131,7 +137,8 @@ onLoad(() => { rank: form.val('rank'), country: form.val('country'), club: form.val('club'), - skip: form.find('input.participation').map((input,i) => [i+1, input.checked]).filter(arr => !arr[1]).map(arr => arr[0]) + skip: form.find('input.participation').map((input,i) => [i+1, input.checked]).filter(arr => !arr[1]).map(arr => arr[0]), + final: form.val('final') } if (form.hasClass('add')) { api.postJson(`tour/${tour_id}/part`, player) @@ -152,6 +159,8 @@ onLoad(() => { } }); $('#players > tbody > tr').on('click', e => { + let regStatus = e.target.closest('td.reg-status'); + if (regStatus) return; let id = e.target.closest('tr').attr('data-id'); api.getJson(`tour/${tour_id}/part/${id}`) .then(player => { @@ -164,6 +173,9 @@ onLoad(() => { form.val('rank', player.rank); form.val('country', player.country); form.val('club', player.club); + form.val('final', player.final); + if (player.final) $('#final-reg').addClass('final'); + else $('#final-reg').removeClass('final'); for (r = 1; r <= tour_rounds; ++r) { form.val(`r${r}`, !(player.skip && player.skip.includes(r))); } @@ -210,4 +222,44 @@ onLoad(() => { } }); }); + $('#reg-status').on('click', e => { + let current = $('#final-reg').hasClass('final'); + if (current) { + $('input[name="final"]')[0].value = false; + $('#final-reg').removeClass('final'); + } else { + $('input[name="final"]')[0].value = true; + $('#final-reg').addClass('final'); + } + }); + $('.reg-status').on('click', e => { + let cell = e.target.closest('td'); + let tr = e.target.closest('tr'); + let id = tr.data('id'); + let newStatus = !cell.hasClass('final'); + api.putJson(`tour/${tour_id}/part/${id}`, { + id: id, + final: newStatus + }).then(player => { + if (player !== 'error') { + cell.toggleClass('final'); + } + }); + e.preventDefault(); + return false; + }); + $('#filter').on('input', (e) => { + let input = e.target; + let value = input.value.toUpperCase(); + if (value === '') $('tbody > tr').removeClass('hidden'); + else $('tbody > tr').forEach(tr => { + let txt = tr.data('text'); + if (txt && txt.indexOf(value) === -1) tr.addClass('hidden'); + else tr.removeClass('hidden'); + }); + }); + $('#filter-box i').on('click', e => { + $('#filter')[0].value = ''; + $('tbody > tr').removeClass('hidden'); + }); }); diff --git a/view-webapp/src/main/webapp/js/tour-results.inc.js b/view-webapp/src/main/webapp/js/tour-results.inc.js index 9320a53..5611892 100644 --- a/view-webapp/src/main/webapp/js/tour-results.inc.js +++ b/view-webapp/src/main/webapp/js/tour-results.inc.js @@ -18,6 +18,7 @@ function setResult(id, result) { } let resultCell = row.find('td.result'); resultCell.text(dispResult).data('result', result); + standingsUpToDate = false; } }) } diff --git a/view-webapp/src/main/webapp/tour-registration.inc.html b/view-webapp/src/main/webapp/tour-registration.inc.html index 379f60c..e69a419 100644 --- a/view-webapp/src/main/webapp/tour-registration.inc.html +++ b/view-webapp/src/main/webapp/tour-registration.inc.html @@ -1,10 +1,18 @@
+
+
+ + +
+
+
#set($parts = $api.get("tour/${params.id}/part")) #set($pmap = $utils.toMap($parts)) + @@ -15,10 +23,14 @@ #foreach($part in $parts) - + + - + @@ -141,6 +153,14 @@
+ +
+ + +
#foreach($r in [1..$tour.rounds])
diff --git a/view-webapp/src/main/webapp/tour-results.inc.html b/view-webapp/src/main/webapp/tour-results.inc.html index 1af39dd..bbbf404 100644 --- a/view-webapp/src/main/webapp/tour-results.inc.html +++ b/view-webapp/src/main/webapp/tour-results.inc.html @@ -14,7 +14,7 @@
-#set($dispRst = {'?':'?', 'w':'w+', 'b':'b+', '=':'=', 'X':'X', '#':'1-1', '0':'0-0'}) +#set($dispRst = {'?':'?', 'w':'1-0', 'b':'0-1', '=':'½-½', 'X':'X', '#':'1-1', '0':'0-0'}) #foreach($game in $games) #set($white = $pmap[$game.w]) #set($black = $pmap[$game.b]) diff --git a/view-webapp/src/main/webapp/tour.html b/view-webapp/src/main/webapp/tour.html index 3a9b291..9857676 100644 --- a/view-webapp/src/main/webapp/tour.html +++ b/view-webapp/src/main/webapp/tour.html @@ -73,6 +73,7 @@ const tour_id = ${tour.id}; const tour_rounds = ${tour.rounds}; let activeRound = ${round}; + let standingsUpToDate = true; // $params #end #set($datepickerLocale = $translate.datepickerLocale($request.lang, $request.loc)) @@ -105,6 +106,9 @@ $('.step').removeClass('active'); $(`.step[data-step="${step}"], #${step}-tab`).addClass('active'); window.location.hash = `#${step}`; + if (step === 'standings' && !standingsUpToDate) { + window.location.reload(); + } } onLoad(() => {
Reg Name First name Country
+ + + $part.name $part.firstname$part.country$part.country.toUpperCase() $part.club #rank($part.rank) $part.rating result