Teams handing in progress
This commit is contained in:
@@ -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()
|
||||
|
@@ -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}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -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}")
|
||||
|
@@ -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
|
||||
}
|
||||
|
@@ -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() })
|
||||
|
@@ -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")
|
||||
}
|
||||
|
||||
|
@@ -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")) }
|
||||
}
|
||||
}
|
@@ -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;
|
||||
|
@@ -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")));
|
||||
}
|
||||
|
44
view-webapp/src/main/webapp/js/tour-teams.inc.js
Normal file
44
view-webapp/src/main/webapp/js/tour-teams.inc.js
Normal 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');
|
||||
}
|
||||
});
|
||||
});
|
@@ -11,7 +11,11 @@
|
||||
#set($round = $math.min($math.max($round, 1), $tour.rounds))
|
||||
#end
|
||||
<div class="section">
|
||||
#set($parts = $api.get("tour/${params.id}/part"))
|
||||
#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>
|
||||
|
@@ -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>
|
||||
|
@@ -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>
|
||||
|
@@ -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 / #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} #end</div>
|
||||
</div>
|
||||
#end
|
||||
|
@@ -1,5 +1,12 @@
|
||||
#set($parts = $api.get("tour/${params.id}/part"))
|
||||
#set($pmap = $utils.toMap($parts))
|
||||
#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)
|
||||
|
@@ -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
|
||||
|
@@ -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])
|
||||
|
34
view-webapp/src/main/webapp/tour-teams.inc.html
Normal file
34
view-webapp/src/main/webapp/tour-teams.inc.html
Normal 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>
|
@@ -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')
|
||||
|
Reference in New Issue
Block a user