Add user games download form

pull/9034/head
Philipp Leclercq 2021-04-26 20:53:25 +02:00 committed by Thibault Duplessis
parent 0a4eb0f9a2
commit 8aa1bcf04d
7 changed files with 270 additions and 7 deletions

View File

@ -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))
)
}

View File

@ -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")
}

View File

@ -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>

View File

@ -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"

View File

@ -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%;
}
}

View File

@ -206,4 +206,8 @@ export default rollupProject({
input: 'src/contact.ts',
output: 'contact',
},
download: {
input: 'src/download.ts',
output: 'download',
},
});

View File

@ -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;