EGF and FFG exports

This commit is contained in:
Claude Brisson
2024-01-01 12:26:40 +01:00
parent 18edd16d6c
commit b261e56807
10 changed files with 218 additions and 54 deletions

View File

@@ -3,21 +3,27 @@ package org.jeudego.pairgoth.api
import com.republicate.kson.Json import com.republicate.kson.Json
import com.republicate.kson.toJsonArray import com.republicate.kson.toJsonArray
import org.jeudego.pairgoth.model.Criterion import org.jeudego.pairgoth.model.Criterion
import org.jeudego.pairgoth.model.Criterion.*
import org.jeudego.pairgoth.model.Game.Result.*
import org.jeudego.pairgoth.model.ID
import org.jeudego.pairgoth.model.MacMahon import org.jeudego.pairgoth.model.MacMahon
import org.jeudego.pairgoth.model.Pairable import org.jeudego.pairgoth.model.Pairable
import org.jeudego.pairgoth.model.PairingType import org.jeudego.pairgoth.model.PairingType
import org.jeudego.pairgoth.model.Tournament
import org.jeudego.pairgoth.model.adjustedTime
import org.jeudego.pairgoth.model.displayRank
import org.jeudego.pairgoth.model.getID
import org.jeudego.pairgoth.model.historyBefore import org.jeudego.pairgoth.model.historyBefore
import org.jeudego.pairgoth.pairing.HistoryHelper import org.jeudego.pairgoth.pairing.HistoryHelper
import org.jeudego.pairgoth.pairing.solver.MacMahonSolver import org.jeudego.pairgoth.pairing.solver.MacMahonSolver
import java.io.PrintWriter
import java.time.format.DateTimeFormatter
import javax.servlet.http.HttpServletRequest import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse import javax.servlet.http.HttpServletResponse
import kotlin.math.max import kotlin.math.max
import kotlin.math.min import kotlin.math.min
import org.jeudego.pairgoth.model.TimeSystem.TimeSystemType.*
import org.jeudego.pairgoth.model.Criterion.* import java.text.DecimalFormat
import org.jeudego.pairgoth.model.Game.Result.*
import org.jeudego.pairgoth.model.ID
import org.jeudego.pairgoth.model.getID
object StandingsHandler: PairgothApiHandler { object StandingsHandler: PairgothApiHandler {
override fun get(request: HttpServletRequest, response: HttpServletResponse): Json? { override fun get(request: HttpServletRequest, response: HttpServletResponse): Json? {
@@ -83,7 +89,7 @@ object StandingsHandler: PairgothApiHandler {
for (crit in criteria) { for (crit in criteria) {
player[crit.first] = crit.second[player.getID()] ?: 0.0 player[crit.first] = crit.second[player.getID()] ?: 0.0
} }
player["results"] = Json.MutableArray(List(round) { "=0" }) player["results"] = Json.MutableArray(List(round) { "0=" })
} }
val sortedPairables = pairables.sortedWith { left, right -> val sortedPairables = pairables.sortedWith { left, right ->
for (crit in criteria) { for (crit in criteria) {
@@ -114,38 +120,156 @@ object StandingsHandler: PairgothApiHandler {
val blackNum = black?.getInt("num") ?: 0 val blackNum = black?.getInt("num") ?: 0
val whiteColor = if (black == null) "" else "w" val whiteColor = if (black == null) "" else "w"
val blackColor = if (white == null) "" else "b" val blackColor = if (white == null) "" else "b"
val handicap = if (game.handicap == 0) "" else "/h${game.handicap}" val handicap = if (game.handicap == 0) "" else "${game.handicap}"
assert(white != null || black != null) assert(white != null || black != null)
if (white != null) { if (white != null) {
val mark = when (game.result) { val mark = when (game.result) {
UNKNOWN -> "?" UNKNOWN -> "?"
BLACK -> "-" BLACK, BOTHLOOSE -> "-"
WHITE -> "+" WHITE, BOTHWIN -> "+"
JIGO -> "=" JIGO, CANCELLED -> "="
CANCELLED -> "X"
BOTHWIN -> "++"
BOTHLOOSE -> "--"
} }
val results = white.getArray("results") as Json.MutableArray val results = white.getArray("results") as Json.MutableArray
results[r - 1] = "$whiteColor$mark$blackNum$handicap" results[r - 1] =
if (blackNum == 0) "0$mark"
else "$blackNum$mark/$whiteColor$handicap"
} }
if (black != null) { if (black != null) {
val mark = when (game.result) { val mark = when (game.result) {
UNKNOWN -> "?" UNKNOWN -> "?"
BLACK -> "+" BLACK, BOTHWIN -> "+"
WHITE -> "-" WHITE, BOTHLOOSE -> "-"
JIGO -> "=" JIGO, CANCELLED -> "="
CANCELLED -> "X"
BOTHWIN -> "++"
BOTHLOOSE -> "--"
} }
val results = black.getArray("results") as Json.MutableArray val results = black.getArray("results") as Json.MutableArray
results[r - 1] = "$blackColor$mark$whiteNum$handicap" results[r - 1] =
if (whiteNum == 0) "0$mark"
else "$whiteNum$mark/$blackColor$handicap"
} }
} }
} }
return sortedPairables.toJsonArray() val accept = request.getHeader("Accept")?.substringBefore(";")
return when(accept) {
"application/json" -> sortedPairables.toJsonArray()
"application/egf" -> {
exportToEGFFormat(tournament, sortedPairables, neededCriteria, response.writer)
return null
}
"application/ffg" -> {
exportToFFGFormat(tournament, sortedPairables, response.writer)
return null
}
else -> ApiHandler.badRequest("invalid Accept header: $accept")
}
} }
val nullMap = mapOf<ID, Double>() val nullMap = mapOf<ID, Double>()
private fun exportToEGFFormat(tournament: Tournament<*>, lines: List<Json.Object>, criteria: List<Criterion>, writer: PrintWriter) {
val mainTime = tournament.timeSystem.mainTime
val adjustedTime = tournament.timeSystem.adjustedTime()
val egfClass =
if (tournament.online) {
when (tournament.timeSystem.type) {
FISCHER ->
if (mainTime >= 1800 && adjustedTime >= 3000) "D"
else "X"
else ->
if (mainTime >= 2400 && adjustedTime >= 3000) "D"
else "X"
}
} else {
when (tournament.timeSystem.type) {
FISCHER ->
if (mainTime >= 2700 && adjustedTime >= 4500) "A"
else if (mainTime >= 1800 && adjustedTime >= 3000) "B"
else if (mainTime >= 1200 && adjustedTime >= 1800) "C"
else "X"
else ->
if (mainTime >= 3600 && adjustedTime >= 4500) "A"
else if (mainTime >= 2400 && adjustedTime >= 3000) "B"
else if (mainTime >= 1500 && adjustedTime >= 1800) "C"
else "X"
}
}
val ret =
"""
; CL[${egfClass}]
; EV[${tournament.name}]
; PC[${tournament.country.lowercase()},${tournament.location}]
; DT[${tournament.startDate},${tournament.endDate}]
; HA[${
if (tournament.pairing.type == PairingType.MAC_MAHON) "h${tournament.pairing.pairingParams.handicap.correction}"
else "h9"
}]
; KM[${tournament.komi}]
; TM[${tournament.timeSystem.adjustedTime() / 60}]
; CM[Generated by Pairgoth v0.1]
;
; Pl Name Rk Co Club ${ criteria.map { it.name.replace(Regex("(S?)O?(SOS|DOS)[MW]?"), "$1$2").padStart(7, ' ') }.joinToString(" ") }
${
lines.joinToString("\n") { player ->
"${
player.getString("num")!!.padStart(4, ' ')
} ${
"${player.getString("name")} ${player.getString("firstname")}".padEnd(30, ' ').take(30)
} ${
displayRank(player.getInt("rank")!!).uppercase().padStart(3, ' ')
} ${
player.getString("country")!!.uppercase()
} ${
(player.getString("club") ?: "").padStart(4).take(4)
} ${
criteria.joinToString(" ") { numFormat.format(player.getDouble(it.name)!!).let { if (it.contains('.')) it else "$it " }.padStart(7, ' ') }
} ${
player.getArray("results")!!.map {
(it as String).padStart(8, ' ')
}.joinToString(" ")
}"
}
}
"""
writer.println(ret)
}
private fun exportToFFGFormat(tournament: Tournament<*>, lines: List<Json.Object>, writer: PrintWriter) {
// let's try in UTF-8
val ret =
""";name=${tournament.shortName}
;date=${frDate.format(tournament.startDate)}
;vill=${tournament.location}${if (tournament.online) "(online)" else ""}
;comm=${tournament.name}
;prog=Pairgoth v0.1
;time=${tournament.timeSystem.mainTime / 60}
;ta=${tournament.timeSystem.adjustedTime() / 60}
;size=${tournament.gobanSize}
;komi=${tournament.komi}
;
;Num Nom Prenom Niv Licence Club
${
lines.joinToString("\n") { player ->
"${
player.getString("num")!!.padStart(4, ' ')
} ${
"${player.getString("name")} ${player.getString("firstname")}".padEnd(24, ' ').take(24)
} ${
displayRank(player.getInt("rank")!!).uppercase().padStart(3, ' ')
} ${
player.getString("ffg") ?: " "
} ${
(player.getString("club") ?: "").padStart(6).take(6)
} ${
player.getArray("results")!!.joinToString(" ") {
(it as String).replace("/", "").replace(Regex("(?<=[bw])$"), "0").padStart(7, ' ')
}
}"
}
}
"""
writer.println(ret)
}
private val numFormat = DecimalFormat("###0.#")
private val frDate: DateTimeFormatter = DateTimeFormatter.ofPattern("dd/MM/yyyy")
} }

View File

@@ -2,7 +2,7 @@ package org.jeudego.pairgoth.ext
import jakarta.xml.bind.JAXBContext import jakarta.xml.bind.JAXBContext
import jakarta.xml.bind.JAXBElement import jakarta.xml.bind.JAXBElement
import kotlinx.datetime.LocalDate import java.time.LocalDate
import org.jeudego.pairgoth.model.* import org.jeudego.pairgoth.model.*
import org.jeudego.pairgoth.opengotha.TournamentType import org.jeudego.pairgoth.opengotha.TournamentType
import org.jeudego.pairgoth.opengotha.ObjectFactory import org.jeudego.pairgoth.opengotha.ObjectFactory
@@ -13,7 +13,7 @@ import javax.xml.datatype.XMLGregorianCalendar
import kotlin.math.roundToInt import kotlin.math.roundToInt
private const val MILLISECONDS_PER_DAY = 86400000 private const val MILLISECONDS_PER_DAY = 86400000
fun XMLGregorianCalendar.toLocalDate() = LocalDate(year, month, day) fun XMLGregorianCalendar.toLocalDate() = LocalDate.of(year, month, day)
object OpenGotha { object OpenGotha {
@@ -114,10 +114,10 @@ object OpenGotha {
location = genParams.location, location = genParams.location,
online = genParams.isBInternet ?: false, online = genParams.isBInternet ?: false,
timeSystem = when (genParams.complementaryTimeSystem) { timeSystem = when (genParams.complementaryTimeSystem) {
"SUDDENDEATH" -> SuddenDeath(genParams.basicTime) "SUDDENDEATH" -> SuddenDeath(genParams.basicTime * 60)
"STDBYOYOMI" -> StandardByoyomi(genParams.basicTime, genParams.stdByoYomiTime, 1) // no periods? "STDBYOYOMI" -> StandardByoyomi(genParams.basicTime * 60, genParams.stdByoYomiTime, 1) // no periods?
"CANBYOYOMI" -> CanadianByoyomi(genParams.basicTime, genParams.canByoYomiTime, genParams.nbMovesCanTime) "CANBYOYOMI" -> CanadianByoyomi(genParams.basicTime * 60, genParams.canByoYomiTime, genParams.nbMovesCanTime)
"FISCHER" -> FischerTime(genParams.basicTime, genParams.fischerTime) "FISCHER" -> FischerTime(genParams.basicTime * 60, genParams.fischerTime)
else -> throw Error("missing byoyomi type") else -> throw Error("missing byoyomi type")
}, },
pairing = when (handParams.hdCeiling) { pairing = when (handParams.hdCeiling) {
@@ -269,9 +269,9 @@ object OpenGotha {
} }
</ByePlayer> </ByePlayer>
<TournamentParameterSet> <TournamentParameterSet>
<GeneralParameterSet bInternet="${tournament.online}" basicTime="${tournament.timeSystem.mainTime}" beginDate="${tournament.startDate}" canByoYomiTime="${tournament.timeSystem.byoyomi}" complementaryTimeSystem="${when(tournament.timeSystem.type) { <GeneralParameterSet bInternet="${tournament.online}" basicTime="${tournament.timeSystem.mainTime / 60}" beginDate="${tournament.startDate}" canByoYomiTime="${tournament.timeSystem.byoyomi}" complementaryTimeSystem="${when(tournament.timeSystem.type) {
TimeSystem.TimeSystemType.SUDDEN_DEATH -> "SUDDENDEATH" TimeSystem.TimeSystemType.SUDDEN_DEATH -> "SUDDENDEATH"
TimeSystem.TimeSystemType.STANDARD -> "STDBYOYOMI" TimeSystem.TimeSystemType.JAPANESE -> "STDBYOYOMI"
TimeSystem.TimeSystemType.CANADIAN -> "CANBYOYOMI" TimeSystem.TimeSystemType.CANADIAN -> "CANBYOYOMI"
TimeSystem.TimeSystemType.FISCHER -> "FISCHER" TimeSystem.TimeSystemType.FISCHER -> "FISCHER"
} }" director="" endDate="${tournament.endDate}" fischerTime="${tournament.timeSystem.increment}" genCountNotPlayedGamesAsHalfPoint="false" genMMBar="${ } }" director="" endDate="${tournament.endDate}" fischerTime="${tournament.timeSystem.increment}" genCountNotPlayedGamesAsHalfPoint="false" genMMBar="${

View File

@@ -1,7 +1,6 @@
package org.jeudego.pairgoth.model package org.jeudego.pairgoth.model
import com.republicate.kson.Json import com.republicate.kson.Json
import org.jeudego.pairgoth.api.ApiHandler
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.model.TimeSystem.TimeSystemType.* import org.jeudego.pairgoth.model.TimeSystem.TimeSystemType.*
@@ -15,7 +14,7 @@ data class TimeSystem(
val stones: Int val stones: Int
) { ) {
companion object {} companion object {}
enum class TimeSystemType { CANADIAN, STANDARD, FISCHER, SUDDEN_DEATH } enum class TimeSystemType { CANADIAN, JAPANESE, FISCHER, SUDDEN_DEATH }
} }
fun CanadianByoyomi(mainTime: Int, byoyomi: Int, stones: Int) = fun CanadianByoyomi(mainTime: Int, byoyomi: Int, stones: Int) =
@@ -30,7 +29,7 @@ fun CanadianByoyomi(mainTime: Int, byoyomi: Int, stones: Int) =
fun StandardByoyomi(mainTime: Int, byoyomi: Int, periods: Int) = fun StandardByoyomi(mainTime: Int, byoyomi: Int, periods: Int) =
TimeSystem( TimeSystem(
type = STANDARD, type = JAPANESE,
mainTime = mainTime, mainTime = mainTime,
increment = 0, increment = 0,
byoyomi = byoyomi, byoyomi = byoyomi,
@@ -86,9 +85,16 @@ fun TimeSystem.Companion.fromJson(json: Json.Object) =
fun TimeSystem.toJson() = when (type) { fun TimeSystem.toJson() = when (type) {
TimeSystem.TimeSystemType.CANADIAN -> Json.Object("type" to type.name, "mainTime" to mainTime, "byoyomi" to byoyomi, "stones" to stones) TimeSystem.TimeSystemType.CANADIAN -> Json.Object("type" to type.name, "mainTime" to mainTime, "byoyomi" to byoyomi, "stones" to stones)
TimeSystem.TimeSystemType.STANDARD -> Json.Object("type" to type.name, "mainTime" to mainTime, "byoyomi" to byoyomi, "periods" to periods) TimeSystem.TimeSystemType.JAPANESE -> Json.Object("type" to type.name, "mainTime" to mainTime, "byoyomi" to byoyomi, "periods" to periods)
TimeSystem.TimeSystemType.FISCHER -> TimeSystem.TimeSystemType.FISCHER ->
if (maxTime == Int.MAX_VALUE) Json.Object("type" to type.name, "mainTime" to mainTime, "increment" to increment) if (maxTime == Int.MAX_VALUE) Json.Object("type" to type.name, "mainTime" to mainTime, "increment" to increment)
else Json.Object("type" to type.name, "mainTime" to mainTime, "increment" to increment, "maxTime" to maxTime) else Json.Object("type" to type.name, "mainTime" to mainTime, "increment" to increment, "maxTime" to maxTime)
TimeSystem.TimeSystemType.SUDDEN_DEATH -> Json.Object("type" to type.name, "mainTime" to mainTime) TimeSystem.TimeSystemType.SUDDEN_DEATH -> Json.Object("type" to type.name, "mainTime" to mainTime)
} }
fun TimeSystem.adjustedTime() = when (type) {
TimeSystem.TimeSystemType.CANADIAN -> mainTime + 60 * byoyomi / stones
TimeSystem.TimeSystemType.JAPANESE -> mainTime + 45 * byoyomi
TimeSystem.TimeSystemType.FISCHER -> mainTime + 120 * increment
TimeSystem.TimeSystemType.SUDDEN_DEATH -> mainTime
}

View File

@@ -2,7 +2,7 @@ package org.jeudego.pairgoth.model
import com.republicate.kson.Json import com.republicate.kson.Json
import com.republicate.kson.toJsonArray import com.republicate.kson.toJsonArray
import kotlinx.datetime.LocalDate import java.time.LocalDate
import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest
import org.jeudego.pairgoth.pairing.solver.MacMahonSolver import org.jeudego.pairgoth.pairing.solver.MacMahonSolver
import org.jeudego.pairgoth.pairing.solver.SwissSolver import org.jeudego.pairgoth.pairing.solver.SwissSolver
@@ -169,8 +169,8 @@ fun Tournament.Companion.fromJson(json: Json.Object, default: Tournament<*>? = n
type = type, type = type,
name = json.getString("name") ?: default?.name ?: badRequest("missing name"), name = json.getString("name") ?: default?.name ?: badRequest("missing name"),
shortName = json.getString("shortName") ?: default?.shortName ?: badRequest("missing shortName"), shortName = json.getString("shortName") ?: default?.shortName ?: badRequest("missing shortName"),
startDate = json.getLocalDate("startDate") ?: default?.startDate ?: badRequest("missing startDate"), startDate = json.getString("startDate")?.let { LocalDate.parse(it) } ?: default?.startDate ?: badRequest("missing startDate"),
endDate = json.getLocalDate("endDate") ?: default?.endDate ?: badRequest("missing endDate"), endDate = json.getString("endDate")?.let { LocalDate.parse(it) } ?: default?.endDate ?: badRequest("missing endDate"),
country = json.getString("country") ?: default?.country ?: badRequest("missing country"), country = json.getString("country") ?: default?.country ?: badRequest("missing country"),
location = json.getString("location") ?: default?.location ?: badRequest("missing location"), location = json.getString("location") ?: default?.location ?: badRequest("missing location"),
online = json.getBoolean("online") ?: default?.online ?: false, online = json.getBoolean("online") ?: default?.online ?: false,
@@ -187,8 +187,8 @@ fun Tournament.Companion.fromJson(json: Json.Object, default: Tournament<*>? = n
type = type, type = type,
name = json.getString("name") ?: default?.name ?: badRequest("missing name"), name = json.getString("name") ?: default?.name ?: badRequest("missing name"),
shortName = json.getString("shortName") ?: default?.shortName ?: badRequest("missing shortName"), shortName = json.getString("shortName") ?: default?.shortName ?: badRequest("missing shortName"),
startDate = json.getLocalDate("startDate") ?: default?.startDate ?: badRequest("missing startDate"), startDate = json.getString("startDate")?.let { LocalDate.parse(it) } ?: default?.startDate ?: badRequest("missing startDate"),
endDate = json.getLocalDate("endDate") ?: default?.endDate ?: badRequest("missing endDate"), endDate = json.getString("endDate")?.let { LocalDate.parse(it) } ?: default?.endDate ?: badRequest("missing endDate"),
country = json.getString("country") ?: default?.country ?: badRequest("missing country"), country = json.getString("country") ?: default?.country ?: badRequest("missing country"),
location = json.getString("location") ?: default?.location ?: badRequest("missing location"), location = json.getString("location") ?: default?.location ?: badRequest("missing location"),
online = json.getBoolean("online") ?: default?.online ?: false, online = json.getBoolean("online") ?: default?.online ?: false,

View File

@@ -218,8 +218,12 @@ class ApiServlet: HttpServlet() {
"Missing 'Accept' header" "Missing 'Accept' header"
) )
// CB TODO 1) a reference to a specific API call at this point is a code smell. // CB TODO 1) a reference to a specific API call at this point is a code smell.
// 2) there will e other content types: .tou, .h9, .html // 2) there will be other content types: .tou, .h9, .html
if (!isJson(accept) && (!isXml(accept) || !request.requestURI.matches(Regex("/api/tour/\\d+")))) throw ApiException( if (!isJson(accept) &&
(!isXml(accept) || !request.requestURI.matches(Regex("/api/tour/\\d+"))) &&
(accept != "application/ffg" && accept != "application/egf" || !request.requestURI.matches(Regex("/api/tour/\\d+/standings/\\d+")))
) throw ApiException(
HttpServletResponse.SC_BAD_REQUEST, HttpServletResponse.SC_BAD_REQUEST,
"Invalid 'Accept' header" "Invalid 'Accept' header"
) )

View File

@@ -153,11 +153,6 @@
<artifactId>kotlin-reflect</artifactId> <artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version> <version>${kotlin.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.jetbrains.kotlinx</groupId>
<artifactId>kotlinx-datetime-jvm</artifactId>
<version>0.4.0</version>
</dependency>
<!-- servlets and mail APIs --> <!-- servlets and mail APIs -->
<dependency> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>

View File

@@ -54,6 +54,11 @@
/* registration section */ /* registration section */
#players-list {
max-width: 95vw;
overflow-x: auto;
}
#player { #player {
&.create { &.create {
.edition { .edition {
@@ -280,4 +285,8 @@
justify-content: space-around; justify-content: space-around;
} }
} }
#standings-container {
max-width: 95vw;
overflow-x: auto;
}
} }

View File

@@ -9,13 +9,16 @@ const apiVersion = '1.0';
// .catch(err => { ... }); // .catch(err => { ... });
const base = '/api/'; const base = '/api/';
let headers = function() { let headers = function(withJson) {
let ret = { let ret = {
"Content-Type": "application/json; charset=utf-8", 'Accept-Version': apiVersion,
"Accept-Version": apiVersion, 'Accept': 'application/json',
"Accept": "application/json", 'X-Browser-Key': store('browserKey')
"X-Browser-Key": store('browserKey')
}; };
if (typeof(withJson) === 'undefined') withJson = true;
if (withJson) {
ret['Content-Type'] = 'application/json';
}
let accessToken = store('accessToken'); let accessToken = store('accessToken');
if (accessToken) { if (accessToken) {
ret['Authorization'] = `Bearer ${accessToken}`; ret['Authorization'] = `Bearer ${accessToken}`;

View File

@@ -1,3 +1,20 @@
function publish(format, extension) {
let form = $('#tournament-infos')[0];
let shortName = form.val('shortName');
let hdrs = headers();
hdrs['Accept'] = `application/${format}`
fetch(`api/tour/${tour_id}/standings/${activeRound}`, {
headers: hdrs
}).then(resp => {
if (resp.ok) return resp.text()
else throw "publish error"
}).then(txt => {
let blob = new Blob(['\uFEFF', txt.trim()], {type: 'plain/text;charset=utf-8'});
downloadFile(blob, `${shortName}.${extension}`);
close_modal();
}).catch(err => showError(err));
}
onLoad(() => { onLoad(() => {
$('.criterium').on('click', e => { $('.criterium').on('click', e => {
let alreadyOpen = e.target.closest('select'); let alreadyOpen = e.target.closest('select');
@@ -45,4 +62,10 @@ onLoad(() => {
$('#publish-modal').on('click', e => { $('#publish-modal').on('click', e => {
close_modal(); close_modal();
}); });
$('.publish-ffg').on('click', e => {
publish('ffg', 'tou');
});
$('.publish-egf').on('click', e => {
publish('egf', 'h9');
});
}); });

View File

@@ -101,9 +101,9 @@
</div> </div>
<div class="popup-footer"> <div class="popup-footer">
<div class="form-actions"> <div class="form-actions">
<button class="ui gray floating cancel button">Cancel</button> <button type="button" class="ui gray floating cancel button">Cancel</button>
<button class="ui blue floating button">EGF</button> <button type="button" class="ui blue floating publish-egf button">EGF</button>
<button class="ui blue floating button">FFG</button> <button type="button" class="ui blue floating publish-ffg button">FFG</button>
</div> </div>
</div> </div>
</div> </div>