Add user games download form
parent
0a4eb0f9a2
commit
8aa1bcf04d
|
@ -5,19 +5,168 @@ import lila.app.templating.Environment._
|
|||
import lila.app.ui.ScalatagsTemplate._
|
||||
|
||||
object download {
|
||||
|
||||
def apply(user: lila.user.User)(implicit ctx: Context) = {
|
||||
def apply(user: lila.user.User)(implicit ctx: Context): Frag = {
|
||||
val title = s"${user.username} • ${trans.exportGames.txt()}"
|
||||
views.html.base.layout(
|
||||
title = title,
|
||||
moreCss = cssTag("form3")
|
||||
moreCss = cssTag("search"),
|
||||
moreJs = jsModule("download")
|
||||
) {
|
||||
main(cls := "box page-small search")(
|
||||
h1(title),
|
||||
form(cls := "form3 box__pad")(
|
||||
"The form here"
|
||||
form(cls := "box__pad search__form")(
|
||||
input(tpe := "hidden", id := "dl-username", value := user.username),
|
||||
table(
|
||||
color,
|
||||
date,
|
||||
opponent,
|
||||
mode,
|
||||
analysis,
|
||||
ongoing,
|
||||
perfToggles,
|
||||
includeToggles,
|
||||
amount,
|
||||
btn,
|
||||
output
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def color(implicit ctx: Context): Frag = tr(
|
||||
th(label(`for` := "dl-color")(trans.search.color())),
|
||||
td(cls := "single")(
|
||||
select(id := "dl-color")(
|
||||
option(value := ""),
|
||||
option(value := "white")(trans.white()),
|
||||
option(value := "black")(trans.black())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private def date(implicit ctx: Context): Frag = tr(
|
||||
th(label(trans.search.date())),
|
||||
td(
|
||||
div(cls := "half")(
|
||||
trans.search.from(),
|
||||
" ",
|
||||
input(tpe := "date", id := "dl-dateMin"),
|
||||
input(tpe := "time", id := "dl-timeMin", step := "1")
|
||||
),
|
||||
div(cls := "half")(
|
||||
trans.search.to(),
|
||||
" ",
|
||||
input(tpe := "date", id := "dl-dateMax"),
|
||||
input(tpe := "time", id := "dl-timeMax", step := "1")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private def opponent(implicit ctx: Context): Frag = tr(
|
||||
th(label(`for` := "dl-opponent")(trans.search.opponentName())),
|
||||
td(input(tpe := "text", id := "dl-opponent"))
|
||||
)
|
||||
|
||||
private def mode(implicit ctx: Context): Frag = tr(
|
||||
th(label(`for` := "dl-rated")(trans.mode())),
|
||||
td(cls := "single")(
|
||||
select(id := "dl-rated")(
|
||||
option(value := ""),
|
||||
option(value := "false")(trans.casual()),
|
||||
option(value := "true")(trans.rated())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private def analysis(implicit ctx: Context): Frag = tr(
|
||||
th(label(`for` := "dl-analysis")(trans.search.analysis())),
|
||||
td(cls := "single")(
|
||||
select(id := "dl-analysis")(
|
||||
option(value := ""),
|
||||
option(value := "true")(trans.yes()),
|
||||
option(value := "false")(trans.no())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private def ongoing(implicit ctx: Context): Frag = tr(
|
||||
th(label(`for` := "dl-ongoing")(trans.currentGames())),
|
||||
td(cmnToggle("dl-ongoing"))
|
||||
)
|
||||
|
||||
private def perfToggles(implicit ctx: Context): Frag = {
|
||||
val perfTypes = lila.rating.PerfType.nonPuzzle
|
||||
tr(
|
||||
th(cls := "top")(label(`for` := "dl-perf-tbl")(trans.variants())),
|
||||
td(
|
||||
table(id := "dl-perf-tbl")(
|
||||
for (i <- perfTypes.indices by 2)
|
||||
yield tr(perfToggle(perfTypes(i)), (i + 1 < perfTypes.length) option perfToggle(perfTypes(i + 1)))
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private def includeToggles(implicit ctx: Context): Frag = tr(
|
||||
th(cls := "top")(
|
||||
label(`for` := "dl-include-tbl")(trans.search.include())
|
||||
),
|
||||
td(
|
||||
table(id := "dl-include-tbl")(
|
||||
tr(
|
||||
th(cls := "quarter")(label(`for` := "dl-tags")(trans.study.pgnTags())),
|
||||
td(cls := "quarter")(cmnToggle("dl-tags", defaultOn = true)),
|
||||
th(cls := "quarter")(label(`for` := "dl-clocks")(trans.moveTimes())),
|
||||
td(cls := "quarter")(cmnToggle("dl-clocks"))
|
||||
),
|
||||
tr(
|
||||
th(cls := "quarter")(label(`for` := "dl-evals")(trans.search.evaluation())),
|
||||
td(cls := "quarter")(cmnToggle("dl-evals")),
|
||||
th(cls := "quarter")(label(`for` := "dl-opening")(trans.opening())),
|
||||
td(cls := "quarter")(cmnToggle("dl-opening"))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private def amount(implicit ctx: Context): Frag = tr(
|
||||
th(
|
||||
label(`for` := "dl-amount")(trans.search.maxNumber()),
|
||||
" ",
|
||||
span(cls := "help", title := trans.search.maxNumberExplanation.txt())("(?)")
|
||||
),
|
||||
td(input(tpe := "number", id := "dl-amount", min := "1", step := "1"))
|
||||
)
|
||||
|
||||
private def btn(implicit ctx: Context): Frag = tr(
|
||||
th,
|
||||
td(cls := "action")(
|
||||
button(cls := "button", tpe := "button", id := "dl-button")(
|
||||
trans.search.generateURL()
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private def output(implicit ctx: Context): Frag = tr(
|
||||
th,
|
||||
td(
|
||||
input(
|
||||
id := "dl-output",
|
||||
cls := "copyable autoselect output",
|
||||
readonly,
|
||||
spellcheck := "false"
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private def cmnToggle(id: String, v: String = "on", defaultOn: Boolean = false): Frag = frag(
|
||||
input(attr("id") := id, tpe := "checkbox", cls := "cmn-toggle", value := v, defaultOn option checked),
|
||||
label(`for` := id)
|
||||
)
|
||||
|
||||
private def perfToggle(perfType: lila.rating.PerfType)(implicit ctx: Context): Frag = frag(
|
||||
th(cls := "quarter")(label(`for` := s"dl-perf-${perfType.key}")(perfType.trans)),
|
||||
td(cls := "quarter")(cmnToggle(id = s"dl-perf-${perfType.key}", v = perfType.key, defaultOn = true))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1655,6 +1655,12 @@ val `date` = new I18nKey("search:date")
|
|||
val `sortBy` = new I18nKey("search:sortBy")
|
||||
val `analysis` = new I18nKey("search:analysis")
|
||||
val `onlyAnalysed` = new I18nKey("search:onlyAnalysed")
|
||||
val `color` = new I18nKey("search:color")
|
||||
val `evaluation` = new I18nKey("search:evaluation")
|
||||
val `maxNumber` = new I18nKey("search:maxNumber")
|
||||
val `maxNumberExplanation` = new I18nKey("search:maxNumberExplanation")
|
||||
val `include` = new I18nKey("search:include")
|
||||
val `generateURL` = new I18nKey("search:generateURL")
|
||||
val `searchInXGames` = new I18nKey("search:searchInXGames")
|
||||
val `xGamesFound` = new I18nKey("search:xGamesFound")
|
||||
}
|
||||
|
|
|
@ -24,4 +24,10 @@
|
|||
<string name="sortBy">Sort by</string>
|
||||
<string name="analysis">Analysis</string>
|
||||
<string name="onlyAnalysed">Only games where a computer analysis is available</string>
|
||||
<string name="color">Color</string>
|
||||
<string name="evaluation">Evaluation</string>
|
||||
<string name="maxNumber">Maximum number</string>
|
||||
<string name="maxNumberExplanation">The maximum number of games to return</string>
|
||||
<string name="include">Include</string>
|
||||
<string name="generateURL">Generate URL</string>
|
||||
</resources>
|
||||
|
|
2
ui/build
2
ui/build
|
@ -19,7 +19,7 @@ mkdir -p public/compiled
|
|||
apps1="common"
|
||||
apps2="chess ceval game tree chat nvui puz"
|
||||
apps3="site swiss msg chat cli challenge notify learn insight editor puzzle round analyse lobby tournament tournamentSchedule tournamentCalendar simul dasher speech palantir serviceWorker dgt storm racer"
|
||||
site_plugins="tvEmbed puzzleEmbed analyseEmbed user modUser clas coordinate captcha expandText team forum account coachShow coachForm challengePage checkout login passwordComplexity tourForm teamBattleForm gameSearch userComplete infiniteScroll flatpickr teamAdmin appeal modGames publicChats contact"
|
||||
site_plugins="tvEmbed puzzleEmbed analyseEmbed user modUser clas coordinate captcha expandText team forum account coachShow coachForm challengePage checkout login passwordComplexity tourForm teamBattleForm gameSearch userComplete infiniteScroll flatpickr teamAdmin appeal modGames publicChats contact download"
|
||||
round_plugins="nvui keyboardMove"
|
||||
analyse_plugins="nvui studyTopicForm"
|
||||
puzzle_plugins="dashboard"
|
||||
|
|
|
@ -25,7 +25,8 @@
|
|||
padding: 0.3em 1em !important;
|
||||
}
|
||||
|
||||
input[type='text'] {
|
||||
input[type='text'],
|
||||
input[type='number'] {
|
||||
width: 86%;
|
||||
}
|
||||
|
||||
|
@ -99,4 +100,18 @@
|
|||
border: $border;
|
||||
border-width: 1px 0;
|
||||
}
|
||||
|
||||
th.top {
|
||||
vertical-align: top;
|
||||
padding-top: 1em;
|
||||
}
|
||||
|
||||
.quarter {
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
.output {
|
||||
visibility: hidden;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,4 +206,8 @@ export default rollupProject({
|
|||
input: 'src/contact.ts',
|
||||
output: 'contact',
|
||||
},
|
||||
download: {
|
||||
input: 'src/download.ts',
|
||||
output: 'download',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
function generateURL() {
|
||||
function addParameter(name: string, value: string | number | boolean): void {
|
||||
if (!url.endsWith('?')) url += '&';
|
||||
url += `${name}=${value}`;
|
||||
}
|
||||
|
||||
let url: string =
|
||||
'https://lichess.org/api/games/user/' +
|
||||
encodeURIComponent((document.getElementById('dl-username') as HTMLInputElement).value) +
|
||||
'?';
|
||||
|
||||
{
|
||||
const minTimestamp = 1356998400070;
|
||||
const midnight = '00:00:00';
|
||||
const dateMin = (document.getElementById('dl-dateMin') as HTMLInputElement).value;
|
||||
const timeMin = (document.getElementById('dl-timeMin') as HTMLInputElement).value;
|
||||
if (dateMin.length == 10) {
|
||||
// the 00:00:00 is necessary for the time to be interpreted in the local timezone
|
||||
const since = new Date(`${dateMin} ${timeMin.length == 8 ? timeMin : midnight}`);
|
||||
addParameter('since', Math.max(since.getTime(), minTimestamp));
|
||||
}
|
||||
|
||||
const dateMax = (document.getElementById('dl-dateMax') as HTMLInputElement).value;
|
||||
const timeMax = (document.getElementById('dl-timeMax') as HTMLInputElement).value;
|
||||
if (dateMax.length == 10) {
|
||||
const until = new Date(`${dateMax} ${timeMax.length == 8 ? timeMax : midnight}`);
|
||||
// If no time is specified, assume that all games on that day should be included
|
||||
if (timeMax.length != 8) until.setDate(until.getDate() + 1);
|
||||
addParameter('until', Math.max(until.getTime(), minTimestamp));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const max = (document.getElementById('dl-amount') as HTMLInputElement).value;
|
||||
if (max.length > 0) addParameter('max', max);
|
||||
|
||||
const vs = (document.getElementById('dl-opponent') as HTMLInputElement).value;
|
||||
if (vs.length > 0) addParameter('vs', encodeURIComponent(vs));
|
||||
|
||||
const rated = (document.getElementById('dl-rated') as HTMLSelectElement).value;
|
||||
if (rated.length > 0) addParameter('rated', rated);
|
||||
}
|
||||
|
||||
{
|
||||
const perfTbl = document.getElementById('dl-perf-tbl') as HTMLTableElement;
|
||||
const toggles = perfTbl.getElementsByClassName('cmn-toggle') as HTMLCollectionOf<HTMLInputElement>;
|
||||
const perfs: Array<string> = [];
|
||||
for (const toggle of toggles) {
|
||||
if (toggle.checked) perfs.push(toggle.value);
|
||||
}
|
||||
// don't add parameter if all or no perf types are selected
|
||||
if (perfs.length > 0 && perfs.length < 14) addParameter('perfType', perfs.join(','));
|
||||
}
|
||||
|
||||
{
|
||||
const color = (document.getElementById('dl-color') as HTMLSelectElement).value;
|
||||
if (color.length > 0) addParameter('color', color);
|
||||
|
||||
const analysed = (document.getElementById('dl-analysis') as HTMLSelectElement).value;
|
||||
if (analysed.length > 0) addParameter('analysed', analysed);
|
||||
|
||||
const ongoing = (document.getElementById('dl-ongoing') as HTMLInputElement).checked;
|
||||
if (ongoing) addParameter('ongoing', ongoing);
|
||||
|
||||
const tags = (document.getElementById('dl-tags') as HTMLInputElement).checked;
|
||||
if (!tags) addParameter('tags', tags);
|
||||
|
||||
const clocks = (document.getElementById('dl-clocks') as HTMLInputElement).checked;
|
||||
if (clocks) addParameter('clocks', clocks);
|
||||
|
||||
const evals = (document.getElementById('dl-evals') as HTMLInputElement).checked;
|
||||
if (evals) addParameter('evals', evals);
|
||||
|
||||
const opening = (document.getElementById('dl-opening') as HTMLInputElement).checked;
|
||||
if (opening) addParameter('opening', opening);
|
||||
}
|
||||
|
||||
const output = document.getElementById('dl-output') as HTMLInputElement;
|
||||
output.value = url;
|
||||
output.style.visibility = 'visible';
|
||||
}
|
||||
|
||||
(document.getElementById('dl-button') as HTMLButtonElement).onclick = generateURL;
|
Loading…
Reference in New Issue