Teams handing in progress

This commit is contained in:
Claude Brisson
2024-04-15 16:33:17 +02:00
parent 2395c4e071
commit 179a502bbc
20 changed files with 249 additions and 68 deletions

View File

@@ -88,7 +88,7 @@ fun Tournament<*>.getSortedPairables(round: Int): List<Json.Object> {
Criterion.DC -> StandingsHandler.nullMap
}
}
val pairables = pairables.values.filter { it.final }.map { it.toMutableJson() }
val pairables = pairables.values.filter { it.final }.map { it.toDetailedJson() }
pairables.forEach { player ->
for (crit in criteria) {
player[crit.first] = (crit.second[player.getID()] ?: 0.0).toInt()

View File

@@ -14,8 +14,8 @@ object PlayerHandler: PairgothApiHandler {
override fun get(request: HttpServletRequest, response: HttpServletResponse): Json? {
val tournament = getTournament(request)
return when (val pid = getSubSelector(request)?.toIntOrNull()) {
null -> tournament.pairables.values.map { it.toJson() }.toJsonArray()
else -> tournament.pairables[pid]?.toJson() ?: badRequest("no player with id #${pid}")
null -> tournament.players.values.map { it.toJson() }.toJsonArray()
else -> tournament.players[pid]?.toJson() ?: badRequest("no player with id #${pid}")
}
}

View File

@@ -14,8 +14,8 @@ object TeamHandler: PairgothApiHandler {
val tournament = getTournament(request)
if (tournament !is TeamTournament) badRequest("tournament is not a team tournament")
return when (val pid = getSubSelector(request)?.toIntOrNull()) {
null -> tournament.teams.values.map { it.toJson() }.toJsonArray()
else -> tournament.teams[pid]?.toJson() ?: badRequest("no team with id #${pid}")
null -> tournament.teams.values.map { it.toDetailedJson() }.toJsonArray()
else -> tournament.teams[pid]?.toDetailedJson() ?: badRequest("no team with id #${pid}")
}
}

View File

@@ -26,12 +26,14 @@ object TournamentHandler: PairgothApiHandler {
else ->
when {
ApiServlet.isJson(accept) -> {
getStore(request).getTournament(id)?.let {
getStore(request).getTournament(id)?.let { tour ->
if (accept == "application/pairgoth") {
it.toFullJson()
tour.toFullJson()
} else {
it.toJson().also { json ->
(json as Json.MutableObject)["stats"] = it.stats()
tour.toJson().also { json ->
// additional attributes for the webapp
json["stats"] = tour.stats()
json["teamSize"] = tour.type.playersNumber
}
}
} ?: badRequest("no tournament with id #${id}")

View File

@@ -8,13 +8,14 @@ import java.util.*
// Pairable
sealed class Pairable(val id: ID, val name: String, open val rating: Int, open val rank: Int, val final: Boolean, val mmsCorrection: Int = 0) {
sealed class Pairable(val id: ID, val name: String, val rating: Int, val rank: Int, val final: Boolean, val mmsCorrection: Int = 0) {
companion object {
const val MIN_RANK: Int = -30 // 30k
const val MAX_RANK: Int = 8 // 9D
}
abstract fun toJson(): Json.Object
fun toJson(): Json.Object = toMutableJson()
abstract fun toMutableJson(): Json.MutableObject
open fun toDetailedJson() = toMutableJson()
abstract val club: String?
abstract val country: String?
open fun fullName(separator: String = " "): String {
@@ -28,9 +29,6 @@ sealed class Pairable(val id: ID, val name: String, open val rating: Int, open v
}
object ByePlayer: Pairable(0, "bye", 0, Int.MIN_VALUE, true) {
override fun toJson(): Json.Object {
throw Error("bye player should never be serialized")
}
override fun toMutableJson(): Json.MutableObject {
throw Error("bye player should never be serialized")
}
@@ -95,7 +93,6 @@ class Player(
}
}
override fun toJson(): Json.Object = toMutableJson()
override fun fullName(separator: String): String {
return name + separator + firstname
}

View File

@@ -8,7 +8,6 @@ import java.time.LocalDate
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.pairing.solver.MacMahonSolver
import org.jeudego.pairgoth.pairing.solver.SwissSolver
import org.jeudego.pairgoth.store.Store
import org.jeudego.pairgoth.store.nextPlayerId
import org.jeudego.pairgoth.store.nextTournamentId
import kotlin.math.max
@@ -172,39 +171,53 @@ class TeamTournament(
gobanSize: Int = 19,
komi: Double = 7.5
): Tournament<TeamTournament.Team>(id, type, name, shortName, startDate, endDate, director, country, location, online, timeSystem, rounds, pairing, rules, gobanSize, komi) {
companion object {}
companion object {
private val epsilon = 0.0001
}
override val players = mutableMapOf<ID, Player>()
val teams: MutableMap<ID, Team> = _pairables
inner class Team(id: ID, name: String, final: Boolean): Pairable(id, name, 0, 0, final) {
private fun List<Int>.average(provider: (Player)->Int) = (sumOf {id -> provider(players[id]!!)} - epsilon / players.size).roundToInt()
inner class Team(id: ID, name: String, rating: Int, rank: Int, final: Boolean, mmsCorrection: Int = 0): Pairable(id, name, rating, rank, final, mmsCorrection) {
val playerIds = mutableSetOf<ID>()
val teamPlayers: Set<Player> 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()
override val rank: Int get() = if (teamPlayers.isEmpty()) super.rank else (teamPlayers.sumOf { player -> player.rank.toDouble() } / players.size).roundToInt()
override val club: String? get() = teamPlayers.map { club }.distinct().let { if (it.size == 1) it[0] else null }
override val country: String? get() = teamPlayers.map { country }.distinct().let { if (it.size == 1) it[0] else null }
val teamPlayers: Set<Player> get() = playerIds.mapNotNull { players[it] }.toSet()
override val club: String? get() = teamPlayers.map { it.club }.distinct().let { if (it.size == 1) it[0] else null }
override val country: String? get() = teamPlayers.map { it.country }.distinct().let { if (it.size == 1) it[0] else null }
override fun toMutableJson() = Json.MutableObject(
"id" to id,
"name" to name,
"players" to playerIds.toList().toJsonArray()
)
override fun toJson(): Json.Object = toMutableJson()
override fun toDetailedJson() = toMutableJson().also { json ->
json["rank"] = rank
country?.also { json["country"] = it }
club?.also { json["club"] = it }
}
val teamOfIndividuals: Boolean get() = type.individual
}
fun teamFromJson(json: Json.Object, default: TeamTournament.Team? = null) = Team(
id = json.getInt("id") ?: default?.id ?: nextPlayerId,
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) {
if (it != null && it is Number) it.toInt().also { id -> players.containsKey(id) }
fun teamFromJson(json: Json.Object, default: TeamTournament.Team? = null): Team {
val teamPlayersIds = json.getArray("players")?.let { arr ->
arr.map {
if (it != null && it is Number) it.toInt().also { id ->
if (!players.containsKey(id)) badRequest("invalid player id: ${id}")
}
else badRequest("invalid players array")
}
} ?: badRequest("missing players")
return Team(
id = json.getInt("id") ?: default?.id ?: nextPlayerId,
name = json.getString("name") ?: default?.name ?: badRequest("missing name"),
rating = json.getInt("rating") ?: default?.rating ?: teamPlayersIds.average(Player::rating),
rank = json.getInt("rank") ?: default?.rank ?: teamPlayersIds.average(Player::rank),
final = teamPlayersIds.all { players[it]!!.final },
mmsCorrection = json.getInt("mmsCorrection") ?: default?.mmsCorrection ?: 0
).also {
it.playerIds.addAll(teamPlayersIds)
}
}
}
// Serialization
@@ -250,10 +263,16 @@ fun Tournament.Companion.fromJson(json: Json.Object, default: Tournament<*>? = n
rounds = json.getInt("rounds") ?: default?.rounds ?: badRequest("missing rounds"),
pairing = json.getObject("pairing")?.let { Pairing.fromJson(it, default?.pairing) } ?: default?.pairing ?: badRequest("missing pairing")
)
(json["players"] as Json.Array?)?.forEach { obj ->
json.getArray("players")?.forEach { obj ->
val pairable = obj as Json.Object
tournament.players[pairable.getID("id")!!] = Player.fromJson(pairable)
}
if (tournament is TeamTournament) {
json.getArray("teams")?.forEach { obj ->
val team = obj as Json.Object
tournament.teams[team.getID("id")!!] = tournament.teamFromJson(team)
}
}
(json["games"] as Json.Array?)?.forEachIndexed { i, arr ->
val round = i + 1
val tournamentGames = tournament.games(round)
@@ -286,7 +305,7 @@ fun Tournament<*>.toJson() = Json.MutableObject(
)
fun Tournament<*>.toFullJson(): Json.Object {
val json = Json.MutableObject(toJson())
val json = toJson()
json["players"] = Json.Array(players.values.map { it.toJson() })
if (this is TeamTournament) {
json["teams"] = Json.Array(teams.values.map { it.toJson() })

View File

@@ -2,11 +2,13 @@ package org.jeudego.pairgoth.test
import com.republicate.kson.Json
import com.republicate.kson.toJsonObject
import com.republicate.kson.toMutableJsonObject
import org.jeudego.pairgoth.model.ID
import org.junit.jupiter.api.MethodOrderer.MethodName
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.TestInstance
import org.junit.jupiter.api.TestMethodOrder
import java.io.Serializable
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
@@ -143,7 +145,13 @@ class BasicTests: TestBase() {
// filter out "id", and also "komi", "rules" and "gobanSize" which were provided by default
// also filter out "pairing", which is filled by all default values
val cmp = Json.Object(*resp.entries.filter { it.key !in listOf("id", "komi", "rules", "gobanSize", "pairing") }.map { Pair(it.key, it.value) }.toTypedArray())
val expected = aTournament.entries.filter { it.key != "pairing" }.map { Pair(it.key, it.value) }.toMap().toJsonObject()
val expected = aTournament.entries.filter { it.key != "pairing" }.map { Pair(it.key, it.value) }.toMap().toMutableJsonObject().also { map ->
map["stats"] = Json.Array(
Json.Object("participants" to 0, "paired" to 0, "games" to 0, "ready" to 0),
Json.Object("participants" to 0, "paired" to 0, "games" to 0, "ready" to 0)
)
map["teamSize"] = 1
}
assertEquals(expected.toString(), cmp.toString(), "tournament differs")
}

View File

@@ -97,4 +97,11 @@ class PairgothTool {
}
fun getRatingsDates() = RatingsManager.getRatingsDates()
fun getTeamables(players: Collection<Json.Object>, teams: Collection<Json.Object>): List<Json.Object> {
val teamed = teams.flatMap { team ->
team.getArray("players")!!.map { it -> it as Long }
}.toSet()
return players.filter { p -> !teamed.contains(p.getLong("id")) }
}
}

View File

@@ -237,6 +237,45 @@
}
}
/* teams section */
#teams-content {
display: flex;
flex-flow: column;
justify-content: start;
align-items: center;
}
#teams-lists {
margin-top: 1em;
flex-grow: 2;
display: flex;
flex-flow: row wrap;
justify-content: center;
gap: 1em;
align-items: start;
}
#teams-buttons {
display: flex;
flex-flow: column nowrap;
justify-content: start;
align-items: stretch;
gap: 1em;
max-width: max(10em, 20vw);
}
#teams-right {
display: inline-flex;
flex-flow: row wrap;
gap: 1em;
flex-shrink: 1;
max-width: max(300px, 60vw);
justify-content: center;
}
#teams {
max-width: max(50vw, 20em);
}
/* pairing section */
#pairing-content {
@@ -428,7 +467,7 @@
}
}
@media(max-width: 1400px) {
@media(max-width: 1600px) {
.ui.steps > .step:not(.active) {
padding-left: 1.2em;
padding-right: 0.8em;

View File

@@ -81,36 +81,43 @@ function updatePairable() {
}
onLoad(()=>{
// note - this handler is also in use for lists on Mac Mahon super groups and teams pages
$('.listitem').on('click', e => {
let listitem = e.target.closest('.listitem');
let box = e.target.closest('.multi-select');
if (e.shiftKey && typeof(focused) !== 'undefined') {
let from = focused.index('.listitem');
let to = e.target.closest('.listitem').index('.listitem');
let to = listitem.index('.listitem');
if (from > to) {
let tmp = from;
from = to;
to = tmp;
}
let parent = e.target.closest('.multi-select');
let children = parent.childNodes.filter('.listitem');
let children = box.childNodes.filter('.listitem');
for (let j = from; j <= to; ++j) { new Tablesort($('#players')[0]);
children.item(j).addClass('selected');
children.item(j).attr('draggable', true);
}
} else {
let target = e.target.closest('.listitem');
if (e.detail === 1) {
focused = target.toggleClass('selected').attr('draggable', target.hasClass('selected'));
} else if (target.closest('#paired')) {
focused = target.attr('draggable', target.hasClass('selected'));
// single click
focused = listitem.toggleClass('selected').attr('draggable', listitem.hasClass('selected'));
} else if (listitem.closest('#pairing-lists')) {
// on pairing page
if (listitem.closest('#paired')) {
// double click
focused = listitem.attr('draggable', listitem.hasClass('selected'));
editGame(focused);
} else {
} else if (listitem.closest('#pairables')) {
editPairable(focused);
}
}
}
box.dispatchEvent(new CustomEvent('listitems'));
});
$('#pair').on('click', e => {
let parts = $('#pairables .selected.listitem').map(item => parseInt(item.data("id")));
if (parts.length == 0) {
if (parts.length) {
$('#pairables .listitem').addClass('selected');
parts = $('#pairables .selected.listitem').map(item => parseInt(item.data("id")));
}

View File

@@ -0,0 +1,44 @@
function teamUp(players) {
api.postJson(`tour/${tour_id}/team`, {
"name": $('#team-name')[0].value,
"players": players
}).then(rst => {
if (rst !== 'error') {
document.location.reload();
}
});
}
function split(teams) {
let promises = teams.map(team => api.deleteJson(`tour/${tour_id}/team/${team}`));
Promise.all(promises)
.then(rsts => {
for (let rst of rsts) {
if (!rst.success) console.error(rst.error)
}
document.location.reload();
});
}
onLoad(() => {
$('#teamup').on('click', e => {
let rows = $('#teamables .selected.listitem')
let players = rows.map(item => parseInt(item.data("id")));
if (players.length !== 0) teamUp(players);
});
$('#split').on('click', e => {
let rows = $('#teams .selected.listitem')
let teams = rows.map(item => parseInt(item.data("id")));
if (teams.length !== 0) split(teams);
});
$('#teamables').on('listitems', () => {
let rows = $('#teamables .selected.listitem');
if (rows.length === teamSize) {
$('#team-name')[0].value = rows.map(row => row.data('name')).join('-');
$('#teamup').removeClass('disabled');
} else {
$('#team-name')[0].value = '';
$('#teamup').addClass('disabled');
}
});
});

View File

@@ -11,7 +11,11 @@
#set($round = $math.min($math.max($round, 1), $tour.rounds))
#end
<div class="section">
#if($tour.type == 'INDIVIDUAL' || $tour.type.startsWith('TEAM'))
#set($parts = $api.get("tour/${params.id}/part"))
#else
#set($parts = $api.get("tour/${params.id}/team"))
#end
#set($pmap = $utils.toMap($parts))
#set($roundPairing = $api.get("tour/${params.id}/pair/$round"))
#if($roundPairing.error)
@@ -46,13 +50,13 @@
<div class="players">
<div class="white player">
<div class="color">White</div>
<div class="name">$white.name $white.firstname #rank($white.rank)<br/>($white.country.toUpperCase(), $white.club)</div>
<div class="name">$white.name $!white.firstname #rank($white.rank)<br/>#if($white.country)($white.country.toUpperCase()#if($white.club), $white.club#end)#end</div>
## <div class="pin">$white.egf</div>
</div>
<div class="equal">½-½</div>
<div class="black player">
<div class="color">Black</div>
<div class="name">$black.name $black.firstname #rank($black.rank)<br/>($black.country.toUpperCase(), $black.club)</div>
<div class="name">$black.name $!black.firstname #rank($black.rank)<br/>#if($black.country)($black.country.toUpperCase()#if($black.club), $black.club#end)#end</div>
## <div class="pin">$black.egf</div>
</div>
</div>

View File

@@ -62,8 +62,8 @@
<span class="info"></span>
<select name="type">
<option value="INDIVIDUAL" #if(!$tour || $tour.type == 'INDIVIDUAL') selected #end>Individual players</option>
#* TODO
<option value="PAIRGO" #if($tour && $tour.type == 'PAIRGO') selected #end>Pair-go tournament</option>
#* TODO
<option value="RENGO2" #if($tour && $tour.type == 'RENGO2') selected #end>Rengo with 2 players teams</option>
<option value="RENGO3" #if($tour && $tour.type == 'RENGO3') selected #end>Rengo with 3 players team</option>
<option value="TEAM2" #if($tour && $tour.type == 'TEAM2') selected #end>Team of 2 individual players</option>

View File

@@ -9,6 +9,13 @@
<div class="title">Registration</div>
</div>
</div>
#if($tour.type != 'INDIVIDUAL')
<div class="step" data-step="teams">
<div class="content">
<div class="title">Teams</div>
</div>
</div>
#end
<div class="step" data-step="pairing">
<div class="content">
<div class="title">Pairing</div>

View File

@@ -27,13 +27,13 @@
<div id="pairables" class="multi-select" title="pairable players">
#foreach($p in $pairables)
#set($part = $pmap[$p])
<div data-id="$part.id" class="listitem pairable"><span class="name">$part.name $part.firstname</span><span>#rank($part.rank) $part.country</span></div>
<div data-id="$part.id" class="listitem pairable"><span class="name">$part.name#if($part.firstname) $part.firstname#end</span><span>#rank($part.rank)#if($part.country) $part.country#end</span></div>
#end
</div>
<div id="unpairables" class="multi-select" title="unpairable players">
#foreach($p in $unpairables)
#set($part = $pmap[$p])
<div data-id="$part.id" class="listitem unpairable"><span class="name">$part.name $part.firstname</span><span>#rank($part.rank) $part.country</span></div>
<div data-id="$part.id" class="listitem unpairable"><span class="name">$part.name#if($part.firstname) $part.firstname#end</span><span>#rank($part.rank)#if($part.country) $part.country#end</span></div>
#end
</div>
</div>
@@ -59,9 +59,9 @@
#set($black = $pmap[$game.b])
<div class="listitem game" data-id="$game.id">
<div class="table" data-value="$game.t">#$game.t</div>
<div class="white" data-id="$game.w">#if($white)$white.name $white.firstname#{else}BIP#end</div>
<div class="white" data-id="$game.w">#if($white)$white.name#if($white.firstname) $white.firstname#end#{else}BIP#end</div>
<div class="levels">#if($white)#rank($white.rank)#end&nbsp;/&nbsp;#if($black)#rank($black.rank)#end</div>
<div class="black" data-id="$game.b">#if($black)$black.name $black.firstname#{else}BIP#end</div>
<div class="black" data-id="$game.b">#if($black)$black.name#if($black.firstname) $black.firstname#end#{else}BIP#end</div>
<div class="handicap" data-value="$game.h">#if($game.h)h$game.h#{else}&nbsp;#end</div>
</div>
#end

View File

@@ -1,5 +1,12 @@
#set($parts = $api.get("tour/${params.id}/part"))
#if($tour.type == 'INDIVIDUAL' || $tour.type.startsWith('TEAM'))
#set($pmap = $utils.toMap($parts))
#else
#set($teams = $api.get("tour/${params.id}/team"))
$log.debug("@@@@@@@@@ teams = $teams")
#set($pmap = $utils.toMap($teams))
#end
<div class="tab-content" id="registration-tab">
<div id="reg-view">
<div id="list-header">
@@ -27,11 +34,11 @@
<th>First name</th>
<th>Country</th>
<th>Club</th>
#if($tour.country == 'FR')
<th>FFG</th>
#else
##if($tour.country == 'FR')
## <th>FFG</th>
##else
<th>PIN</th>
#end
##end
<th>Rank</th>
## TableSort bug which inverts specified sort...
<th data-sort-default="1" aria-sort="ascending">Rating</th>
@@ -77,7 +84,7 @@
<i class="plus icon"></i>
Add player
</button>
#if($tour.pairing.type == 'MAC_MAHON')
#if($tour.type == 'INDIVIDUAL' && $tour.pairing.type == 'MAC_MAHON')
<button id="edit-macmahon-groups" class="ui right labeled icon floating button">
<i class="pencil icon"></i>
Mac Mahon groups
@@ -238,7 +245,7 @@
<div class="success-feedback"><i class="big green check icon"></i></div>
</div>
</div>
#if($tour.pairing.type == 'MAC_MAHON')
#if($tour.type == 'INDIVIDUAL' && $tour.pairing.type == 'MAC_MAHON')
#set($mmbase = $api.get("tour/${params.id}/standings/0"))
#if($mmbase.isObject() && ($mmbase.error || $mmbase.message))
#if($mmbase.error)

View File

@@ -30,8 +30,8 @@
#if($black && $white)
<tr id="result-$game.id" data-id="$game.id">
<td data-sort="$game.t">#$game.t</td>
<td class="white player #if($game.r == 'w' || $game.r == '#') winner #elseif($game.r == 'b' || $game.r == '0') looser #end" data-id="$white.id" data-sort="$white.name $white.firstname"><span>#if($white)$white.name $white.firstname #rank($white.rank)#{else}BIP#end</span></td>
<td class="black player #if($game.r == 'b' || $game.r == '#') winner #elseif($game.r == 'w' || $game.r == '0') looser #end" data-id="$black.id" data-sort="$black.name $black.firstname"><span>#if($black)$black.name $black.firstname #rank($black.rank)#{else}BIP#end</span></td>
<td class="white player #if($game.r == 'w' || $game.r == '#') winner #elseif($game.r == 'b' || $game.r == '0') looser #end" data-id="$white.id" data-sort="$white.name#if($white.firstname) $white.firstname#end"><span>#if($white)$white.name#if($white.firstname) $white.firstname#end #rank($white.rank)#{else}BIP#end</span></td>
<td class="black player #if($game.r == 'b' || $game.r == '#') winner #elseif($game.r == 'w' || $game.r == '0') looser #end" data-id="$black.id" data-sort="$black.name#if($black.firstname) $black.firstname#end"><span>#if($black)$black.name#if($black.firstname) $black.firstname#end #rank($black.rank)#{else}BIP#end</span></td>
<td class="result centered" data-sort="$game.r" data-result="$game.r">$dispRst[$game.r]</td>
</tr>
#end

View File

@@ -65,9 +65,9 @@
<tr>
<td>$part.num</td>
<td>$part.place</td>
<td>$part.name $part.firstname</td>
<td>$part.name#if($part.firstname) $part.firstname#end</td>
<td data-sort="$part.rank">#rank($part.rank)</td>
<td>$part.country</td>
<td>#if($part.country)$part.country#end</td>
<td>$number.format('0.#', $part.NBW)</td>
#set($mx = $round - 1)
#foreach($r in [0..$mx])

View File

@@ -0,0 +1,34 @@
#set($teamables = $utils.getTeamables($parts, $teams))
<div class="tab-content" id="teams-tab">
<div id="teams-content">
<div id="teams-lists">
<div id="teams-left">
<div id="teamables" class="multi-select" title="team members">
#foreach($part in $teamables)
<div data-id="$part.id" data-name="$part.name" class="listitem pairable"><span class="name">$part.name $part.firstname</span><span>#rank($part.rank) $part.country</span></div>
#end
</div>
</div>
<div id="teams-right">
<div id="teams-buttons">
<div class="vert flex">
<input type="text" id="team-name" placeholder="team name"/>
<button id="teamup" class="ui blue right labeled icon floating disabled button">
<i class="angle double right icon"></i>
Team up
</button>
</div>
<button id="split" class="ui orange right labeled icon floating button">
<i class="angle double left icon"></i>
Split
</button>
</div>
<div id="teams" class="multi-select" title="teams">
#foreach($team in $teams)
<div data-id="$team.id" class="listitem team"><span class="name">$team.name</span><span>#rank($team.rank)#if($team.country) $team.country#end</span></div>
#end
</div>
</div>
</div>
</div>
</div>

View File

@@ -38,6 +38,9 @@
#translate('tour-information.inc.html')
#if($tour)
#translate('tour-registration.inc.html')
#if($tour.type != 'INDIVIDUAL')
#translate('tour-teams.inc.html')
#end
#translate('tour-pairing.inc.html')
#translate('tour-results.inc.html')
#translate('tour-standings.inc.html')
@@ -54,7 +57,7 @@
let correction = #if($tour.pairing.type == 'MAC_MAHON')${tour.pairing.handicap.correction}#{else}0#end;
let standingsUpToDate = true;
let pairablesUpToDate = true;
// $params
const teamSize = $tour.teamSize;
#end
#set($datepickerLocale = $translate.datepickerLocale($request.lang, $request.loc))
const datepickerLocale = '$datepickerLocale';
@@ -162,6 +165,9 @@
#include('/js/tour-information.inc.js')
#if($tour)
#include('/js/tour-registration.inc.js')
#if($tour.type != 'INDIVIDUAL')
#include('/js/tour-teams.inc.js')
#end
#include('/js/tour-pairing.inc.js')
#include('/js/tour-results.inc.js')
#include('/js/tour-standings.inc.js')