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 bee62a4..b88ec86 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 @@ -3,6 +3,7 @@ package org.jeudego.pairgoth.model import com.republicate.kson.Json import org.jeudego.pairgoth.api.ApiHandler.Companion.badRequest import org.jeudego.pairgoth.store.Store +import java.util.* // Pairable @@ -51,6 +52,13 @@ fun Pairable.Companion.parseRank(rankStr: String): Int { // Player +enum class DatabaseId { + AGA, + EGF, + FFG; + val key get() = this.name.lowercase(Locale.ROOT) +} + class Player( id: ID, name: String, @@ -62,7 +70,7 @@ class Player( ): Pairable(id, name, rating, rank) { companion object // used to store external IDs ("FFG" => FFG ID, "EGF" => EGF PIN, "AGA" => AGA ID ...) - val externalIds = mutableMapOf() + val externalIds = mutableMapOf() override fun toJson(): Json.Object = Json.MutableObject( "id" to id, "name" to name, @@ -71,8 +79,11 @@ class Player( "rank" to rank, "country" to country, "club" to club - ).also { - if (skip.isNotEmpty()) it["skip"] = Json.Array(skip) + ).also { json -> + if (skip.isNotEmpty()) json["skip"] = Json.Array(skip) + externalIds.forEach { (dbid, id) -> + json[dbid.key] = id + } } override fun nameSeed(separator: String): String { return name + separator + firstname @@ -92,4 +103,9 @@ fun Player.Companion.fromJson(json: Json.Object, default: Player? = null) = Play json.getArray("skip")?.let { if (it.isNotEmpty()) player.skip.addAll(it.map { id -> (id as Number).toInt() }) } + DatabaseId.values().forEach { dbid -> + json.getString(dbid.key)?.let { id -> + player.externalIds[dbid] = id + } + } } diff --git a/view-webapp/src/main/kotlin/org/jeudego/pairgoth/web/DispatchingFilter.kt b/view-webapp/src/main/kotlin/org/jeudego/pairgoth/web/DispatchingFilter.kt index 6d6c06c..f6e82a5 100644 --- a/view-webapp/src/main/kotlin/org/jeudego/pairgoth/web/DispatchingFilter.kt +++ b/view-webapp/src/main/kotlin/org/jeudego/pairgoth/web/DispatchingFilter.kt @@ -32,7 +32,7 @@ class DispatchingFilter : Filter { when { uri.endsWith('/') -> response.sendRedirect("${uri}index") uri.contains('.') -> - if (uri.endsWith(".html")) resp.sendError(404) + if (uri.endsWith(".html") || uri.contains(".inc.")) resp.sendError(404) else defaultRequestDispatcher.forward(request, response) else -> chain.doFilter(request, response) } diff --git a/view-webapp/src/main/sass/tour.scss b/view-webapp/src/main/sass/tour.scss index 1b832af..8f1dbec 100644 --- a/view-webapp/src/main/sass/tour.scss +++ b/view-webapp/src/main/sass/tour.scss @@ -1,4 +1,18 @@ @layer pairgoth { + /* general rules */ + + .steps .step:not(.active) { + cursor: pointer; + } + .tab-content { + display: none; + &.active { + display: block; + } + } + + /* information section */ + #tournament-infos { input, select, .edit { display: none; @@ -19,22 +33,15 @@ margin: 1px; background-color: #eeeeee; } - .steps .step:not(.active) { - cursor: pointer; - } - .section.info { - #pairing, #standings { - display: none; - } - } - .section.pairing { - #tournament-infos, #standings { - display: none; - } - } - .section.standings { - #tournament-infos, #pairing { - display: none; + + /* registration section */ + + #registration { + display: flex; + flex-flow: row wrap; + justify-content: space-between; + > .roundbox { + flex: 1; } } } diff --git a/view-webapp/src/main/webapp/js/tour-information.inc.js b/view-webapp/src/main/webapp/js/tour-information.inc.js new file mode 100644 index 0000000..34e351e --- /dev/null +++ b/view-webapp/src/main/webapp/js/tour-information.inc.js @@ -0,0 +1,157 @@ +onLoad(() => { + $('#edit').on('click', e => { + e.preventDefault(); + $('#tournament-infos').addClass('edit'); + return false; + }); + + $('#cancel, #close').on('click', e => { + e.preventDefault(); + if ($('#tournament-infos').hasClass('edit')) { + $('#tournament-infos').removeClass('edit') + } else { + document.location.href = '/index'; + } + return false; + }); + + $('#validate').on('click', e => { + let valid = true; + // validate required fields + let required = ['name', 'shortName', 'startDate', 'endDate']; + if (!$('input[name="online"]')[0].checked) required.push('location') + for (let name of required) { + let ctl = $(`input[name=${name}]`)[0]; + let val = ctl.value; + if (val) { + ctl.setCustomValidity(''); + } else { + valid = false; + ctl.setCustomValidity(msg('required_field')); + } + } + if (!valid) return; + // validate short_name + let shortNameCtl = $('input[name="shortName"]')[0]; + let shortName = shortNameCtl.value; + if (safeRegex.test(shortName)) { + shortNameCtl.setCustomValidity(''); + } else { + valid = false; + shortNameCtl.setCustomValidity(msg('invalid_character')); + } + if (!valid) return; + }); + + for(let name of ['startDate', 'endDate']) { + let control = $(`input[name="${name}"]`)[0]; + if (control.value) { + control.value = formatDate(control.value); + } + } + new DateRangePicker($('#date-range')[0], { + autohide: true, + language: datepickerLocale || 'en' + }); + + $('input[name="online"]').on('change', e => { + $('input[name="location"]')[0].disabled = e.target.checked; + }); + + $('select[name="timeSystemType"]').on('change', e => { + switch (e.target.value) { + case 'CANADIAN': + $('#increment').addClass('hidden'); + $('#maxTime').addClass('hidden'); + $('#byoyomi').removeClass('hidden'); + $('#periods').addClass('hidden'); + $('#stones').removeClass('hidden'); + break; + case 'FISCHER': + $('#increment').removeClass('hidden'); + $('#maxTime').removeClass('hidden'); + $('#byoyomi').addClass('hidden'); + $('#periods').addClass('hidden'); + $('#stones').addClass('hidden'); + break; + case 'STANDARD': + $('#increment').addClass('hidden'); + $('#maxTime').addClass('hidden'); + $('#byoyomi').removeClass('hidden'); + $('#periods').removeClass('hidden'); + $('#stones').addClass('hidden'); + break; + case 'SUDDEN_DEATH': + $('#increment').addClass('hidden'); + $('#maxTime').addClass('hidden'); + $('#byoyomi').addClass('hidden'); + $('#periods').addClass('hidden'); + $('#stones').addClass('hidden'); + break; + } + }); + + $('input.duration').imask({ + mask: '00:00:00', + lazy: false, + overwrite: true + }); + + $('#tournament-infos').on('submit', e => { + e.preventDefault(); + let tour = { + name: formValue('name'), + shortName: formValue('shortName'), + startDate: parseDate(formValue('startDate')), + endDate: parseDate(formValue('endDate')), + type: formValue('type'), + rounds: formValue('rounds'), + country: formValue('country'), + online: formValue('online'), + location: formValue('online') ? "" : formValue('location'), + pairing: { + type: formValue('pairing'), + // mmFloor: formValue('mmFloor'), + mmBar: formValue('mmBar'), + main: { + firstSeed: formValue('firstSeed'), + secondSeed: formValue('secondSeed') + }, + handicap: { + correction: formValue('correction'), + treshold: formValue('treshold') + } + }, + timeSystem: { + type: formValue('timeSystemType'), + mainTime: fromHMS(formValue('mainTime')), + increment: fromHMS(formValue('increment')), + maxTime: fromHMS(formValue('maxTime')), + byoyomi: fromHMS(formValue('byoyomi')), + periods: formValue('periods'), + stones: formValue('stones') + } + } + console.log(tour); + if (typeof(tour_id) !== 'undefined') { + api.putJson(`tour/${tour_id}`, tour) + .then(tour => { + window.location.reload(); + }); + } else { + api.postJson('tour', tour) + .then(tour => { + window.location.href += `?id=${tour.id}`; + }); + } + }); + + if (!window.location.hash && window.location.search) { + window.location.hash = '#information' + } + if (window.location.hash) { + let step = window.location.hash.substring(1); + chooseStep(step); + } + +}); diff --git a/view-webapp/src/main/webapp/tour-information.inc.html b/view-webapp/src/main/webapp/tour-information.inc.html new file mode 100644 index 0000000..2118d98 --- /dev/null +++ b/view-webapp/src/main/webapp/tour-information.inc.html @@ -0,0 +1,234 @@ +
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + from + + + to + + + +
+
+
+
+ + + +
+
+ + + +
+ or + +
+
+
+
+
+
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+#* MM floor parameter not shown on creation page + +*# + + + +
+ +
+ + + +
+
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ + + +
+
+
+
+ +#if($tour) + + +#end + +
+
+
diff --git a/view-webapp/src/main/webapp/tour-pairing.inc.html b/view-webapp/src/main/webapp/tour-pairing.inc.html new file mode 100644 index 0000000..8d80304 --- /dev/null +++ b/view-webapp/src/main/webapp/tour-pairing.inc.html @@ -0,0 +1,3 @@ +
+ Pairing... +
diff --git a/view-webapp/src/main/webapp/tour-registration.inc.html b/view-webapp/src/main/webapp/tour-registration.inc.html new file mode 100644 index 0000000..94f23ac --- /dev/null +++ b/view-webapp/src/main/webapp/tour-registration.inc.html @@ -0,0 +1,15 @@ +
+
+ Players list +
+
+
+ +
+
+
+ \ No newline at end of file diff --git a/view-webapp/src/main/webapp/tour-results.inc.html b/view-webapp/src/main/webapp/tour-results.inc.html new file mode 100644 index 0000000..67b7ee3 --- /dev/null +++ b/view-webapp/src/main/webapp/tour-results.inc.html @@ -0,0 +1,3 @@ +
+ Results... +
diff --git a/view-webapp/src/main/webapp/tour-standings.inc.html b/view-webapp/src/main/webapp/tour-standings.inc.html new file mode 100644 index 0000000..050eacd --- /dev/null +++ b/view-webapp/src/main/webapp/tour-standings.inc.html @@ -0,0 +1,3 @@ +
+ Standings... +
diff --git a/view-webapp/src/main/webapp/tour.html b/view-webapp/src/main/webapp/tour.html index f839729..46bc400 100644 --- a/view-webapp/src/main/webapp/tour.html +++ b/view-webapp/src/main/webapp/tour.html @@ -20,278 +20,53 @@ #end #end
-

#if($tour)$tour.name#{else}New tournament#end

+

#if($tour)$tour.name#{else}New Tournament#end

#if($tour)
-
+
Information
-
name, place and date
+
+
+
+
+
Registration
Pairing
-
teams or players, rounds
+
+
+
+
+
Results
Standings
-
pairing system
+ #translate('tour-registration.inc.html') + #translate('tour-pairing.inc.html') + #translate('tour-results.inc.html') + #translate('tour-standings.inc.html') #end -
-
-
-
- - - -
-
- - - -
-
-
-
- - - from - - - to - - - -
-
-
-
- - - -
-
- - - -
- or - -
-
-
-
-
-
-
- - - -
-
- - - -
-
-
-
- - - -
-#* MM floor parameter not shown on creation page - -*# - - - -
- -
- - - -
-
-
-
-
- - - -
-
- - - -
-
- - - -
-
-
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
-
-
- -#if($tour) - - -#end - -
-
-
- Pairing... -
-
- Standings... -
+#translate('tour-information.inc.html')
diff --git a/view-webapp/src/main/webapp/tournament-form.inc.html b/view-webapp/src/main/webapp/tournament-form.inc.html deleted file mode 100644 index 71a22f9..0000000 --- a/view-webapp/src/main/webapp/tournament-form.inc.html +++ /dev/null @@ -1,84 +0,0 @@ -
-
-
- - -
-
- - -
-
- - from to -
-
- - rounds -
-
-
-
- -
-
- -
-
-
-
- -
-
-
-
- -
-
-
-
-
-
- -
-
- -
-
-
-
- -
-
-
-
-
- - - -CB TODO : -s'il y a duplication du formulaire (pour nouveau/édition), il faut changer les ids en class, gérer les pbs d'init du date-range, etc. -sinon, il faut paramétrer la dialog (mais les steps 1/2/3 deviennent des tabs, etc.) - -Donc dans tous les cas il y a qqc à faire !