get rid of twirl
parent
3cae3ceb33
commit
f81b9db930
|
@ -2,7 +2,6 @@ package lila.app
|
|||
package actor
|
||||
|
||||
import akka.actor._
|
||||
import play.twirl.api.Html
|
||||
|
||||
import lila.game.Pov
|
||||
import views.{ html => V }
|
||||
|
|
|
@ -49,7 +49,7 @@ object Blog extends LilaController {
|
|||
blogApi context req flatMap { implicit prismic =>
|
||||
blogApi.recent(prismic.api, none, 1, lila.common.MaxPerPage(50)) map {
|
||||
_ ?? { docs =>
|
||||
Ok(views.xml.blog.atom(docs)) as XML
|
||||
Ok(views.html.blog.atom(docs)) as XML
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package controllers
|
|||
import chess.format.Forsyth
|
||||
import chess.Situation
|
||||
import play.api.libs.json._
|
||||
import play.twirl.api.Html
|
||||
|
||||
import lila.app._
|
||||
import lila.game.GameRepo
|
||||
|
|
|
@ -6,7 +6,6 @@ import play.api.http._
|
|||
import play.api.libs.json.{ Json, JsObject, JsArray, JsString, Writes }
|
||||
import play.api.mvc._
|
||||
import play.api.mvc.BodyParsers.parse
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.Frag
|
||||
|
||||
import lila.api.{ PageData, Context, HeaderContext, BodyContext }
|
||||
|
@ -32,8 +31,6 @@ private[controllers] trait LilaController
|
|||
def fuccess = scala.concurrent.Future successful result
|
||||
}
|
||||
|
||||
protected implicit def LilaHtmlToResult(content: Html): Result = Ok(content)
|
||||
|
||||
protected implicit def LilaFragToResult(frag: Frag): Result = Ok(frag)
|
||||
|
||||
protected implicit def makeApiVersion(v: Int) = ApiVersion(v)
|
||||
|
|
|
@ -4,7 +4,6 @@ import play.api.data.Form
|
|||
import play.api.libs.iteratee._
|
||||
import play.api.libs.json._
|
||||
import play.api.mvc._
|
||||
import play.twirl.api.Html
|
||||
import scala.concurrent.duration._
|
||||
|
||||
import lila.api.{ Context, BodyContext }
|
||||
|
@ -275,36 +274,36 @@ object User extends LilaController {
|
|||
Env.pref.api.getPref(user).logTimeIfGt(s"$username pref.getPref", 2 seconds) flatMap {
|
||||
case history ~ charges ~ reports ~ pref =>
|
||||
Env.user.lightUserApi.preloadMany(reports.userIds).logTimeIfGt(s"$username lightUserApi.preloadMany", 2 seconds) inject
|
||||
Html(html.user.mod.parts(user, history, charges, reports, pref).render).some
|
||||
html.user.mod.parts(user, history, charges, reports, pref).some
|
||||
}
|
||||
val actions = UserRepo.isErased(user) map { erased =>
|
||||
Html(html.user.mod.actions(user, emails, erased).render).some
|
||||
html.user.mod.actions(user, emails, erased).some
|
||||
}
|
||||
val spyFu = Env.security.userSpy(user).logTimeIfGt(s"$username security.userSpy", 2 seconds)
|
||||
val others = spyFu flatMap { spy =>
|
||||
val familyUserIds = user.id :: spy.otherUserIds.toList
|
||||
Env.user.noteApi.forMod(familyUserIds).logTimeIfGt(s"$username noteApi.forMod", 2 seconds) zip
|
||||
Env.playban.api.bans(familyUserIds).logTimeIfGt(s"$username playban.bans", 2 seconds) map {
|
||||
case notes ~ bans => Html(html.user.mod.otherUsers(user, spy, notes, bans).render).some
|
||||
case notes ~ bans => html.user.mod.otherUsers(user, spy, notes, bans).some
|
||||
}
|
||||
}
|
||||
val identification = spyFu map { spy =>
|
||||
Html(html.user.mod.identification(user, spy).render).some
|
||||
html.user.mod.identification(user, spy).some
|
||||
}
|
||||
val irwin = Env.irwin.api.reports.withPovs(user) map {
|
||||
_ ?? { reps =>
|
||||
Html(html.irwin.report(reps).render).some
|
||||
html.irwin.report(reps).some
|
||||
}
|
||||
}
|
||||
val assess = Env.mod.assessApi.getPlayerAggregateAssessmentWithGames(user.id) flatMap {
|
||||
_ ?? { as =>
|
||||
Env.user.lightUserApi.preloadMany(as.games.flatMap(_.userIds)) inject Html(html.user.mod.assessments(as).render).some
|
||||
Env.user.lightUserApi.preloadMany(as.games.flatMap(_.userIds)) inject html.user.mod.assessments(as).some
|
||||
}
|
||||
}
|
||||
import play.api.libs.EventSource
|
||||
implicit val extractor = EventSource.EventDataExtractor[Html](_.toString)
|
||||
implicit val extractor = EventSource.EventDataExtractor[scalatags.Text.Frag](_.render)
|
||||
Ok.chunked {
|
||||
(Enumerator(Html(html.user.mod.menu(user).render)) interleave
|
||||
(Enumerator(html.user.mod.menu(user)) interleave
|
||||
futureToEnumerator(parts.logTimeIfGt(s"$username parts", 2 seconds)) interleave
|
||||
futureToEnumerator(actions.logTimeIfGt(s"$username actions", 2 seconds)) interleave
|
||||
futureToEnumerator(others.logTimeIfGt(s"$username others", 2 seconds)) interleave
|
||||
|
|
|
@ -24,8 +24,7 @@ object Environment
|
|||
with SecurityHelper
|
||||
with TeamHelper
|
||||
with TournamentHelper
|
||||
with ChessgroundHelper
|
||||
with ui.ScalatagsTwirl {
|
||||
with ChessgroundHelper {
|
||||
|
||||
type FormWithCaptcha = (play.api.data.Form[_], lila.common.Captcha)
|
||||
|
||||
|
|
|
@ -2,33 +2,29 @@ package lila.app
|
|||
package templating
|
||||
|
||||
import play.api.data._
|
||||
import play.twirl.api.Html
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app.ui.ScalatagsTemplate._
|
||||
import lila.i18n.I18nDb
|
||||
|
||||
trait FormHelper { self: I18nHelper =>
|
||||
|
||||
def errMsg(form: Field)(implicit ctx: Context): Html = errMsg(form.errors)
|
||||
def errMsg(form: Field)(implicit ctx: Context): Frag = errMsg(form.errors)
|
||||
|
||||
def errMsg(form: Form[_])(implicit ctx: Context): Html = errMsg(form.errors)
|
||||
def errMsg(form: Form[_])(implicit ctx: Context): Frag = errMsg(form.errors)
|
||||
|
||||
def errMsg(error: FormError)(implicit ctx: Context): Html = Html {
|
||||
s"""<p class="error">${transKey(error.message, I18nDb.Site, error.args).render}</p>"""
|
||||
}
|
||||
def errMsg(error: FormError)(implicit ctx: Context): Frag =
|
||||
p(cls := "error")(transKey(error.message, I18nDb.Site, error.args))
|
||||
|
||||
def errMsg(errors: Seq[FormError])(implicit ctx: Context): Html = Html {
|
||||
def errMsg(errors: Seq[FormError])(implicit ctx: Context): Frag =
|
||||
errors map errMsg mkString
|
||||
}
|
||||
|
||||
def globalError(form: Form[_])(implicit ctx: Context): Option[Html] =
|
||||
def globalError(form: Form[_])(implicit ctx: Context): Option[Frag] =
|
||||
form.globalError map errMsg
|
||||
|
||||
val booleanChoices = Seq("true" -> "✓ Yes", "false" -> "✗ No")
|
||||
|
||||
object form3 extends ui.ScalatagsPlay {
|
||||
|
||||
import ui.ScalatagsTemplate._
|
||||
object form3 {
|
||||
|
||||
private val idPrefix = "form3"
|
||||
|
||||
|
@ -54,10 +50,6 @@ trait FormHelper { self: I18nHelper =>
|
|||
case ("constraint.max", Seq(m: Int)) => max := m
|
||||
}
|
||||
|
||||
/* All public methods must return HTML
|
||||
* because twirl just calls toString on scalatags frags
|
||||
* and that escapes the content :( */
|
||||
|
||||
val split = div(cls := "form-split")
|
||||
|
||||
def group(
|
||||
|
@ -66,18 +58,17 @@ trait FormHelper { self: I18nHelper =>
|
|||
klass: String = "",
|
||||
half: Boolean = false,
|
||||
help: Option[Frag] = None
|
||||
)(content: Field => Frag)(implicit ctx: Context): Html =
|
||||
div(cls := List(
|
||||
"form-group" -> true,
|
||||
"is-invalid" -> field.hasErrors,
|
||||
"form-half" -> half,
|
||||
klass -> klass.nonEmpty
|
||||
))(
|
||||
groupLabel(field)(labelContent),
|
||||
content(field),
|
||||
errors(field),
|
||||
help map { helper(_) }
|
||||
)
|
||||
)(content: Field => Frag)(implicit ctx: Context): Frag = div(cls := List(
|
||||
"form-group" -> true,
|
||||
"is-invalid" -> field.hasErrors,
|
||||
"form-half" -> half,
|
||||
klass -> klass.nonEmpty
|
||||
))(
|
||||
groupLabel(field)(labelContent),
|
||||
content(field),
|
||||
errors(field),
|
||||
help map { helper(_) }
|
||||
)
|
||||
|
||||
def input(field: Field, typ: String = "", klass: String = ""): BaseTagType =
|
||||
st.input(
|
||||
|
@ -88,66 +79,60 @@ trait FormHelper { self: I18nHelper =>
|
|||
cls := List("form-control" -> true, klass -> klass.nonEmpty)
|
||||
)(validationModifiers(field))
|
||||
|
||||
def inputHtml(field: Field, typ: String = "", klass: String = "")(modifiers: Modifier*): Html =
|
||||
input(field, typ, klass)(modifiers)
|
||||
|
||||
def checkbox(
|
||||
field: Field,
|
||||
labelContent: Frag,
|
||||
half: Boolean = false,
|
||||
help: Option[Frag] = None,
|
||||
disabled: Boolean = false
|
||||
): Html =
|
||||
div(cls := List(
|
||||
"form-check form-group" -> true,
|
||||
"form-half" -> half
|
||||
))(
|
||||
div(
|
||||
span(cls := "form-check-input")(
|
||||
st.input(
|
||||
st.id := id(field),
|
||||
name := field.name,
|
||||
value := "true",
|
||||
tpe := "checkbox",
|
||||
cls := "form-control cmn-toggle",
|
||||
field.value.has("true") option checked,
|
||||
disabled option st.disabled
|
||||
),
|
||||
label(`for` := id(field))
|
||||
): Frag = div(cls := List(
|
||||
"form-check form-group" -> true,
|
||||
"form-half" -> half
|
||||
))(
|
||||
div(
|
||||
span(cls := "form-check-input")(
|
||||
st.input(
|
||||
st.id := id(field),
|
||||
name := field.name,
|
||||
value := "true",
|
||||
tpe := "checkbox",
|
||||
cls := "form-control cmn-toggle",
|
||||
field.value.has("true") option checked,
|
||||
disabled option st.disabled
|
||||
),
|
||||
groupLabel(field)(labelContent)
|
||||
label(`for` := id(field))
|
||||
),
|
||||
help map { helper(_) }
|
||||
)
|
||||
groupLabel(field)(labelContent)
|
||||
),
|
||||
help map { helper(_) }
|
||||
)
|
||||
|
||||
def select(
|
||||
field: Field,
|
||||
options: Iterable[(Any, String)],
|
||||
default: Option[String] = None
|
||||
): Html =
|
||||
st.select(
|
||||
st.id := id(field),
|
||||
name := field.name,
|
||||
cls := "form-control"
|
||||
)(validationModifiers(field))(
|
||||
default map { option(value := "")(_) },
|
||||
options.toSeq map {
|
||||
case (value, name) => option(
|
||||
st.value := value.toString,
|
||||
field.value.has(value.toString) option selected
|
||||
)(name)
|
||||
}
|
||||
)
|
||||
): Frag = st.select(
|
||||
st.id := id(field),
|
||||
name := field.name,
|
||||
cls := "form-control"
|
||||
)(validationModifiers(field))(
|
||||
default map { option(value := "")(_) },
|
||||
options.toSeq map {
|
||||
case (value, name) => option(
|
||||
st.value := value.toString,
|
||||
field.value.has(value.toString) option selected
|
||||
)(name)
|
||||
}
|
||||
)
|
||||
|
||||
def textarea(
|
||||
field: Field,
|
||||
klass: String = ""
|
||||
)(modifiers: Modifier*): Html =
|
||||
st.textarea(
|
||||
st.id := id(field),
|
||||
name := field.name,
|
||||
cls := List("form-control" -> true, klass -> klass.nonEmpty)
|
||||
)(validationModifiers(field))(modifiers)(~field.value)
|
||||
)(modifiers: Modifier*): Frag = st.textarea(
|
||||
st.id := id(field),
|
||||
name := field.name,
|
||||
cls := List("form-control" -> true, klass -> klass.nonEmpty)
|
||||
)(validationModifiers(field))(modifiers)(~field.value)
|
||||
|
||||
val actions = div(cls := "form-actions")
|
||||
val action = div(cls := "form-actions single")
|
||||
|
@ -158,7 +143,7 @@ trait FormHelper { self: I18nHelper =>
|
|||
nameValue: Option[(String, String)] = None,
|
||||
klass: String = "",
|
||||
confirm: Option[String] = None
|
||||
): Html = button(
|
||||
): Frag = button(
|
||||
tpe := "submit",
|
||||
dataIcon := icon,
|
||||
name := nameValue.map(_._1),
|
||||
|
@ -172,13 +157,12 @@ trait FormHelper { self: I18nHelper =>
|
|||
title := confirm
|
||||
)(content)
|
||||
|
||||
def hidden(field: Field, value: Option[String] = None): Html =
|
||||
st.input(
|
||||
st.id := id(field),
|
||||
name := field.name,
|
||||
st.value := value.orElse(field.value),
|
||||
tpe := "hidden"
|
||||
)
|
||||
def hidden(field: Field, value: Option[String] = None): Frag = st.input(
|
||||
st.id := id(field),
|
||||
name := field.name,
|
||||
st.value := value.orElse(field.value),
|
||||
tpe := "hidden"
|
||||
)
|
||||
|
||||
def password(field: Field, content: Frag)(implicit ctx: Context): Frag =
|
||||
group(field, content)(input(_, typ = "password")(required))
|
||||
|
@ -186,20 +170,20 @@ trait FormHelper { self: I18nHelper =>
|
|||
def passwordModified(field: Field, content: Frag)(modifiers: Modifier*)(implicit ctx: Context): Frag =
|
||||
group(field, content)(input(_, typ = "password")(required)(modifiers))
|
||||
|
||||
def globalError(form: Form[_])(implicit ctx: Context): Option[Html] =
|
||||
def globalError(form: Form[_])(implicit ctx: Context): Option[Frag] =
|
||||
form.globalError map { err =>
|
||||
div(cls := "form-group is-invalid")(error(err))
|
||||
}
|
||||
|
||||
def flatpickr(field: Field, withTime: Boolean = true): Html =
|
||||
def flatpickr(field: Field, withTime: Boolean = true): Frag =
|
||||
input(field, klass = "flatpickr")(
|
||||
dataEnableTime := withTime,
|
||||
datatime24h := withTime
|
||||
)
|
||||
|
||||
object file {
|
||||
def image(name: String): Html = st.input(tpe := "file", st.name := name, accept := "image/*")
|
||||
def pgn(name: String): Html = st.input(tpe := "file", st.name := name, accept := ".pgn")
|
||||
def image(name: String): Frag = st.input(tpe := "file", st.name := name, accept := "image/*")
|
||||
def pgn(name: String): Frag = st.input(tpe := "file", st.name := name, accept := ".pgn")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ import lila.app.ui.ScalatagsTemplate._
|
|||
import lila.common.String.frag.escapeHtml
|
||||
import lila.game.{ Game, Player, Namer, Pov }
|
||||
import lila.i18n.{ I18nKeys, enLang }
|
||||
import lila.user.{ User, UserContext }
|
||||
import lila.user.{ User, UserContext, Title }
|
||||
|
||||
trait GameHelper { self: I18nHelper with UserHelper with AiHelper with StringHelper with ChessgroundHelper =>
|
||||
|
||||
|
@ -78,7 +78,7 @@ trait GameHelper { self: I18nHelper with UserHelper with AiHelper with StringHel
|
|||
}
|
||||
|
||||
def shortClockName(clock: Option[Clock.Config])(implicit ctx: UserContext): Frag =
|
||||
clock.fold[Frag](I18nKeys.unlimited.frag())(shortClockName)
|
||||
clock.fold[Frag](I18nKeys.unlimited())(shortClockName)
|
||||
|
||||
def shortClockName(clock: Clock.Config): Frag = raw(clock.show)
|
||||
|
||||
|
@ -92,8 +92,17 @@ trait GameHelper { self: I18nHelper with UserHelper with AiHelper with StringHel
|
|||
case Mode.Rated => I18nKeys.rated.literalTxtTo(enLang)
|
||||
}
|
||||
|
||||
def playerUsername(player: Player, withRating: Boolean = true, withTitle: Boolean = true) =
|
||||
Namer.player(player, withRating, withTitle)(lightUser)
|
||||
def playerUsername(player: Player, withRating: Boolean = true, withTitle: Boolean = true): Frag = raw {
|
||||
player.aiLevel.fold(
|
||||
player.userId.flatMap(lightUser).fold(lila.user.User.anonymous) { user =>
|
||||
val title = withTitle ?? user.title ?? { t =>
|
||||
s"""<span class="title"${(Title(t) == Title.BOT) ?? " data-bot"} title="${Title titleName Title(t)}">$t</span> """
|
||||
}
|
||||
if (withRating) s"$title${user.name} (${lila.game.Namer ratingString player})"
|
||||
else s"$title${user.name}"
|
||||
}
|
||||
) { level => s"A.I. level $level" }
|
||||
}
|
||||
|
||||
def playerText(player: Player, withRating: Boolean = false) =
|
||||
Namer.playerText(player, withRating)(lightUser)
|
||||
|
|
|
@ -8,7 +8,7 @@ import lila.app.ui.ScalatagsTemplate._
|
|||
import lila.common.String.frag.escapeHtml
|
||||
import lila.team.Env.{ current => teamEnv }
|
||||
|
||||
trait TeamHelper extends ui.ScalatagsTwirl {
|
||||
trait TeamHelper {
|
||||
|
||||
private def api = teamEnv.api
|
||||
|
||||
|
|
|
@ -234,7 +234,7 @@ trait UserHelper { self: I18nHelper with StringHelper with NumberHelper =>
|
|||
}
|
||||
|
||||
def userGameFilterTitle(u: User, nbs: UserInfo.NbGames, filter: GameFilter)(implicit ctx: UserContext): Frag =
|
||||
if (filter == GameFilter.Search) frag(br, trans.advancedSearch.frag())
|
||||
if (filter == GameFilter.Search) frag(br, trans.advancedSearch())
|
||||
else splitNumber(userGameFilterTitleNoTag(u, nbs, filter))
|
||||
|
||||
def userGameFilterTitleNoTag(u: User, nbs: UserInfo.NbGames, filter: GameFilter)(implicit ctx: UserContext): String = (filter match {
|
||||
|
|
|
@ -3,8 +3,6 @@ package ui
|
|||
|
||||
import ornicar.scalalib.Zero
|
||||
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.all.{ genericAttr, attr, StringFrag }
|
||||
import scalatags.text.Builder
|
||||
import scalatags.Text.{ Aggregate, Cap }
|
||||
import scalatags.Text.all._
|
||||
|
@ -95,38 +93,12 @@ trait ScalatagsTemplate extends Styles
|
|||
|
||||
val trans = lila.i18n.I18nKeys
|
||||
def main = scalatags.Text.tags2.main
|
||||
}
|
||||
|
||||
object ScalatagsTemplate extends ScalatagsTemplate
|
||||
|
||||
// what to import in all twirl templates
|
||||
trait ScalatagsTwirl extends ScalatagsPlay
|
||||
|
||||
// what to import in twirl templates containing scalatags forms
|
||||
// Allows `*.rows := 5`
|
||||
trait ScalatagsTwirlForm extends ScalatagsPlay with Cap with Aggregate {
|
||||
object * extends Cap with Attrs with ScalatagsAttrs
|
||||
}
|
||||
object ScalatagsTwirlForm extends ScalatagsTwirlForm
|
||||
|
||||
// interop with play
|
||||
trait ScalatagsPlay {
|
||||
|
||||
/* Feed frags back to twirl by converting them to rendered Html */
|
||||
implicit def fragToPlayHtml(frag: Frag): Html = Html(frag.render)
|
||||
|
||||
/* Use play Html inside tags without double-encoding */
|
||||
implicit def playHtmlToFrag(html: Html): Frag = RawFrag(html.body)
|
||||
|
||||
/* Convert play URLs to scalatags attributes with toString */
|
||||
implicit val playCallAttr = genericAttr[play.api.mvc.Call]
|
||||
|
||||
@inline implicit def fragToHtml(frag: Frag) = new FragToHtml(frag)
|
||||
}
|
||||
|
||||
final class FragToHtml(private val self: Frag) extends AnyVal {
|
||||
def toHtml: Html = Html(self.render)
|
||||
}
|
||||
object ScalatagsTemplate extends ScalatagsTemplate
|
||||
|
||||
// generic extensions
|
||||
trait ScalatagsExtensions {
|
||||
|
|
|
@ -14,15 +14,15 @@ object close {
|
|||
active = "close"
|
||||
) {
|
||||
div(cls := "account box box-pad")(
|
||||
h1(dataIcon := "j", cls := "text")(trans.closeAccount.frag()),
|
||||
h1(dataIcon := "j", cls := "text")(trans.closeAccount()),
|
||||
st.form(cls := "form3", action := routes.Account.closeConfirm, method := "POST")(
|
||||
div(cls := "form-group")(trans.closeAccountExplanation.frag()),
|
||||
div(cls := "form-group")(trans.closeAccountExplanation()),
|
||||
div(cls := "form-group")("You will not be allowed to open a new account with the same name, even if the case if different."),
|
||||
form3.passwordModified(form("passwd"), trans.password.frag())(autocomplete := "off"),
|
||||
form3.passwordModified(form("passwd"), trans.password())(autocomplete := "off"),
|
||||
form3.actions(frag(
|
||||
a(href := routes.User.show(u.username))(trans.changedMindDoNotCloseAccount.frag()),
|
||||
a(href := routes.User.show(u.username))(trans.changedMindDoNotCloseAccount()),
|
||||
form3.submit(
|
||||
trans.closeAccount.frag(),
|
||||
trans.closeAccount(),
|
||||
icon = "j".some,
|
||||
confirm = "Closing is definitive. There is no going back. Are you sure?".some,
|
||||
klass = "button-red"
|
||||
|
|
|
@ -15,14 +15,14 @@ object email {
|
|||
) {
|
||||
div(cls := "account box box-pad")(
|
||||
h1(
|
||||
trans.changeEmail.frag(),
|
||||
trans.changeEmail(),
|
||||
ctx.req.queryString.contains("ok") option
|
||||
frag(" ", i(cls := "is-green", dataIcon := "E"))
|
||||
),
|
||||
st.form(cls := "form3", action := routes.Account.emailApply, method := "POST")(
|
||||
form3.password(form("passwd"), trans.password.frag()),
|
||||
form3.group(form("email"), trans.email.frag())(form3.input(_, typ = "email")(required)),
|
||||
form3.action(form3.submit(trans.apply.frag()))
|
||||
form3.password(form("passwd"), trans.password()),
|
||||
form3.group(form("email"), trans.email())(form3.input(_, typ = "email")(required)),
|
||||
form3.action(form3.submit(trans.apply()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -26,13 +26,13 @@ object emailConfirmHelp {
|
|||
form3.split(
|
||||
form3.group(
|
||||
form("username"),
|
||||
trans.username.frag(),
|
||||
trans.username(),
|
||||
help = raw("What username did you create?").some
|
||||
) { f =>
|
||||
form3.input(f)(pattern := lila.user.User.newUsernameRegex.regex)
|
||||
},
|
||||
div(cls := "form-group")(
|
||||
form3.submit(trans.apply.frag())
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
)
|
||||
),
|
||||
|
|
|
@ -14,8 +14,8 @@ object kid {
|
|||
active = "kid"
|
||||
) {
|
||||
div(cls := "account box box-pad")(
|
||||
h1(trans.kidMode.frag()),
|
||||
p(trans.kidModeExplanation.frag()),
|
||||
h1(trans.kidMode()),
|
||||
p(trans.kidModeExplanation()),
|
||||
br,
|
||||
br,
|
||||
br,
|
||||
|
@ -31,7 +31,7 @@ object kid {
|
|||
),
|
||||
br,
|
||||
br,
|
||||
p(trans.inKidModeTheLichessLogoGetsIconX.frag(raw(s"""<span title="${trans.kidMode()}" class="kiddo">😊</span>""")))
|
||||
p(trans.inKidModeTheLichessLogoGetsIconX(raw(s"""<span title="${trans.kidMode()}" class="kiddo">😊</span>""")))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,28 +27,28 @@ object layout {
|
|||
)
|
||||
},
|
||||
a(activeCls("kid"), href := routes.Account.kid())(
|
||||
trans.kidMode.frag()
|
||||
trans.kidMode()
|
||||
),
|
||||
div(cls := "sep"),
|
||||
a(activeCls("editProfile"), href := routes.Account.profile())(
|
||||
trans.editProfile.frag()
|
||||
trans.editProfile()
|
||||
),
|
||||
isGranted(_.Coach) option a(activeCls("coach"), href := routes.Coach.edit)("Coach profile"),
|
||||
div(cls := "sep"),
|
||||
a(activeCls("password"), href := routes.Account.passwd())(
|
||||
trans.changePassword.frag()
|
||||
trans.changePassword()
|
||||
),
|
||||
a(activeCls("email"), href := routes.Account.email())(
|
||||
trans.changeEmail.frag()
|
||||
trans.changeEmail()
|
||||
),
|
||||
a(activeCls("username"), href := routes.Account.username())(
|
||||
trans.changeUsername.frag()
|
||||
trans.changeUsername()
|
||||
),
|
||||
a(activeCls("twofactor"), href := routes.Account.twoFactor())(
|
||||
"Two-factor authentication"
|
||||
),
|
||||
a(activeCls("security"), href := routes.Account.security())(
|
||||
trans.security.frag()
|
||||
trans.security()
|
||||
),
|
||||
div(cls := "sep"),
|
||||
a(href := routes.Plan.index)("Patron"),
|
||||
|
@ -59,7 +59,7 @@ object layout {
|
|||
ctx.noBot option a(activeCls("oauth.app"), href := routes.OAuthApp.index)("OAuth Apps"),
|
||||
div(cls := "sep"),
|
||||
a(activeCls("close"), href := routes.Account.close())(
|
||||
trans.closeAccount.frag()
|
||||
trans.closeAccount()
|
||||
)
|
||||
),
|
||||
div(cls := "page-menu__content")(body)
|
||||
|
|
|
@ -15,15 +15,15 @@ object passwd {
|
|||
) {
|
||||
div(cls := "account box box-pad")(
|
||||
h1(
|
||||
trans.changePassword.frag(),
|
||||
trans.changePassword(),
|
||||
ctx.req.queryString.contains("ok") option
|
||||
frag(" ", i(cls := "is-green", dataIcon := "E"))
|
||||
),
|
||||
st.form(cls := "form3", action := routes.Account.passwdApply, method := "POST")(
|
||||
form3.password(form("oldPasswd"), trans.currentPassword.frag()),
|
||||
form3.password(form("newPasswd1"), trans.newPassword.frag()),
|
||||
form3.password(form("newPasswd2"), trans.newPasswordAgain.frag()),
|
||||
form3.action(form3.submit(trans.apply.frag()))
|
||||
form3.password(form("oldPasswd"), trans.currentPassword()),
|
||||
form3.password(form("newPasswd1"), trans.newPassword()),
|
||||
form3.password(form("newPasswd2"), trans.newPasswordAgain()),
|
||||
form3.action(form3.submit(trans.apply()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -44,117 +44,117 @@ object pref {
|
|||
st.form(cls := "autosubmit", action := routes.Pref.formApply, method := "POST")(
|
||||
categFieldset(PrefCateg.GameDisplay, categ)(
|
||||
setting(
|
||||
trans.pieceAnimation.frag(),
|
||||
trans.pieceAnimation(),
|
||||
radios(form("display.animation"), translatedAnimationChoices)
|
||||
),
|
||||
setting(
|
||||
trans.materialDifference.frag(),
|
||||
trans.materialDifference(),
|
||||
radios(form("display.captured"), booleanChoices)
|
||||
),
|
||||
setting(
|
||||
trans.boardHighlights.frag(),
|
||||
trans.boardHighlights(),
|
||||
radios(form("display.highlight"), booleanChoices)
|
||||
),
|
||||
setting(
|
||||
trans.pieceDestinations.frag(),
|
||||
trans.pieceDestinations(),
|
||||
radios(form("display.destination"), booleanChoices)
|
||||
),
|
||||
setting(
|
||||
trans.boardCoordinates.frag(),
|
||||
trans.boardCoordinates(),
|
||||
radios(form("display.coords"), translatedBoardCoordinateChoices)
|
||||
),
|
||||
setting(
|
||||
trans.moveListWhilePlaying.frag(),
|
||||
trans.moveListWhilePlaying(),
|
||||
radios(form("display.replay"), translatedMoveListWhilePlayingChoices)
|
||||
),
|
||||
setting(
|
||||
trans.pgnPieceNotation.frag(),
|
||||
trans.pgnPieceNotation(),
|
||||
radios(form("display.pieceNotation"), translatedPieceNotationChoices)
|
||||
),
|
||||
setting(
|
||||
trans.zenMode.frag(),
|
||||
trans.zenMode(),
|
||||
radios(form("display.zen"), booleanChoices)
|
||||
),
|
||||
setting(
|
||||
trans.blindfoldChess.frag(),
|
||||
trans.blindfoldChess(),
|
||||
radios(form("display.blindfold"), translatedBlindfoldChoices)
|
||||
)
|
||||
),
|
||||
categFieldset(PrefCateg.ChessClock, categ)(
|
||||
setting(
|
||||
trans.tenthsOfSeconds.frag(),
|
||||
trans.tenthsOfSeconds(),
|
||||
radios(form("clockTenths"), translatedClockTenthsChoices)
|
||||
),
|
||||
setting(
|
||||
trans.horizontalGreenProgressBars.frag(),
|
||||
trans.horizontalGreenProgressBars(),
|
||||
radios(form("clockBar"), booleanChoices)
|
||||
),
|
||||
setting(
|
||||
trans.soundWhenTimeGetsCritical.frag(),
|
||||
trans.soundWhenTimeGetsCritical(),
|
||||
radios(form("clockSound"), booleanChoices)
|
||||
)
|
||||
),
|
||||
categFieldset(PrefCateg.GameBehavior, categ)(
|
||||
setting(
|
||||
trans.howDoYouMovePieces.frag(),
|
||||
trans.howDoYouMovePieces(),
|
||||
radios(form("behavior.moveEvent"), translatedMoveEventChoices)
|
||||
),
|
||||
setting(
|
||||
trans.premovesPlayingDuringOpponentTurn.frag(),
|
||||
trans.premovesPlayingDuringOpponentTurn(),
|
||||
radios(form("behavior.premove"), booleanChoices)
|
||||
),
|
||||
setting(
|
||||
trans.takebacksWithOpponentApproval.frag(),
|
||||
trans.takebacksWithOpponentApproval(),
|
||||
radios(form("behavior.takeback"), translatedTakebackChoices)
|
||||
),
|
||||
setting(
|
||||
trans.promoteToQueenAutomatically.frag(),
|
||||
trans.promoteToQueenAutomatically(),
|
||||
radios(form("behavior.autoQueen"), translatedAutoQueenChoices)
|
||||
),
|
||||
setting(
|
||||
trans.claimDrawOnThreefoldRepetitionAutomatically.frag(),
|
||||
trans.claimDrawOnThreefoldRepetitionAutomatically(),
|
||||
radios(form("behavior.autoThreefold"), translatedAutoThreefoldChoices)
|
||||
),
|
||||
setting(
|
||||
trans.moveConfirmation.frag(),
|
||||
trans.moveConfirmation(),
|
||||
radios(form("behavior.submitMove"), submitMoveChoices)
|
||||
),
|
||||
setting(
|
||||
trans.confirmResignationAndDrawOffers.frag(),
|
||||
trans.confirmResignationAndDrawOffers(),
|
||||
radios(form("behavior.confirmResign"), confirmResignChoices)
|
||||
),
|
||||
setting(
|
||||
trans.inputMovesWithTheKeyboard.frag(),
|
||||
trans.inputMovesWithTheKeyboard(),
|
||||
radios(form("behavior.keyboardMove"), booleanChoices)
|
||||
),
|
||||
setting(
|
||||
trans.castleByMovingTheKingTwoSquaresOrOntoTheRook.frag(),
|
||||
trans.castleByMovingTheKingTwoSquaresOrOntoTheRook(),
|
||||
radios(form("behavior.rookCastle"), translatedRookCastleChoices)
|
||||
)
|
||||
),
|
||||
categFieldset(PrefCateg.Privacy, categ)(
|
||||
setting(
|
||||
trans.letOtherPlayersFollowYou.frag(),
|
||||
trans.letOtherPlayersFollowYou(),
|
||||
radios(form("follow"), booleanChoices)
|
||||
),
|
||||
setting(
|
||||
trans.letOtherPlayersChallengeYou.frag(),
|
||||
trans.letOtherPlayersChallengeYou(),
|
||||
radios(form("challenge"), translatedChallengeChoices)
|
||||
),
|
||||
setting(
|
||||
trans.letOtherPlayersMessageYou.frag(),
|
||||
trans.letOtherPlayersMessageYou(),
|
||||
radios(form("message"), translatedMessageChoices)
|
||||
),
|
||||
setting(
|
||||
trans.letOtherPlayersInviteYouToStudy.frag(),
|
||||
trans.letOtherPlayersInviteYouToStudy(),
|
||||
radios(form("studyInvite"), translatedStudyInviteChoices)
|
||||
),
|
||||
setting(
|
||||
trans.shareYourInsightsData.frag(),
|
||||
trans.shareYourInsightsData(),
|
||||
radios(form("insightShare"), translatedInsightSquareChoices)
|
||||
)
|
||||
),
|
||||
p(cls := "saved text none", dataIcon := "E")(trans.yourPreferencesHaveBeenSaved.frag())
|
||||
p(cls := "saved text none", dataIcon := "E")(trans.yourPreferencesHaveBeenSaved())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -24,29 +24,29 @@ object profile {
|
|||
st.form(cls := "form3", action := routes.Account.profileApply, method := "POST")(
|
||||
div(cls := "form-group")(trans.allInformationIsPublicAndOptional()),
|
||||
form3.split(
|
||||
form3.group(form("country"), trans.country.frag(), half = true) { f =>
|
||||
form3.group(form("country"), trans.country(), half = true) { f =>
|
||||
form3.select(f, lila.user.Countries.allPairs, default = "".some)
|
||||
},
|
||||
form3.group(form("location"), trans.location.frag(), half = true)(form3.input(_))
|
||||
form3.group(form("location"), trans.location(), half = true)(form3.input(_))
|
||||
),
|
||||
NotForKids {
|
||||
form3.group(form("bio"), trans.biography.frag(), help = trans.biographyDescription.frag().some) { f =>
|
||||
form3.group(form("bio"), trans.biography(), help = trans.biographyDescription().some) { f =>
|
||||
form3.textarea(f)(rows := 5)
|
||||
}
|
||||
},
|
||||
form3.split(
|
||||
form3.group(form("firstName"), trans.firstName.frag(), half = true)(form3.input(_)),
|
||||
form3.group(form("lastName"), trans.lastName.frag(), half = true)(form3.input(_))
|
||||
form3.group(form("firstName"), trans.firstName(), half = true)(form3.input(_)),
|
||||
form3.group(form("lastName"), trans.lastName(), half = true)(form3.input(_))
|
||||
),
|
||||
form3.split(
|
||||
List("fide", "uscf", "ecf").map { rn =>
|
||||
form3.group(form(s"${rn}Rating"), trans.xRating.frag(rn.toUpperCase), help = trans.ifNoneLeaveEmpty.frag().some, klass = "form-third")(form3.input(_, typ = "number"))
|
||||
form3.group(form(s"${rn}Rating"), trans.xRating(rn.toUpperCase), help = trans.ifNoneLeaveEmpty().some, klass = "form-third")(form3.input(_, typ = "number"))
|
||||
}
|
||||
),
|
||||
form3.group(form("links"), raw("Social media links "), help = Some(linksHelp)) { f =>
|
||||
form3.textarea(f)(rows := 5)
|
||||
},
|
||||
form3.action(form3.submit(trans.apply.frag()))
|
||||
form3.action(form3.submit(trans.apply()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -12,14 +12,14 @@ object security {
|
|||
def apply(u: lila.user.User, sessions: List[lila.security.LocatedSession], curSessionId: String)(implicit ctx: Context) =
|
||||
account.layout(title = s"${u.username} - ${trans.security.txt()}", active = "security") {
|
||||
div(cls := "account security box")(
|
||||
h1(trans.security.frag()),
|
||||
h1(trans.security()),
|
||||
div(cls := "box__pad")(
|
||||
p(trans.thisIsAListOfDevicesThatHaveLoggedIntoYourAccount.frag()),
|
||||
p(trans.thisIsAListOfDevicesThatHaveLoggedIntoYourAccount()),
|
||||
sessions.length > 1 option div(
|
||||
trans.alternativelyYouCanX.frag {
|
||||
trans.alternativelyYouCanX {
|
||||
form(cls := "revoke-all", action := routes.Account.signout("all"), method := "POST")(
|
||||
button(tpe := "submit", cls := "button button-empty button-red confirm")(
|
||||
trans.revokeAllSessions.frag()
|
||||
trans.revokeAllSessions()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ object twoFactor {
|
|||
qrCode,
|
||||
div(cls := "form-group explanation")("Enter your password and the authentication code generated by the app to complete the setup. You will need an authentication code every time you log in."),
|
||||
form3.hidden(form("secret")),
|
||||
form3.password(form("passwd"), trans.password.frag()),
|
||||
form3.password(form("passwd"), trans.password()),
|
||||
form3.group(form("token"), raw("Authentication code"))(form3.input(_)(pattern := "[0-9]{6}", autocomplete := "off", required)),
|
||||
form3.globalError(form),
|
||||
div(cls := "form-group")("Note: If you lose access to your two-factor authentication codes, you can do a password reset via email."),
|
||||
|
@ -54,7 +54,7 @@ object twoFactor {
|
|||
"You need your password and an authentication code from your authenticator app to disable two-factor authentication. ",
|
||||
"If you lost access to your authentication codes, you can also do a password reset via email."
|
||||
),
|
||||
form3.password(form("passwd"), trans.password.frag()),
|
||||
form3.password(form("passwd"), trans.password()),
|
||||
form3.group(form("token"), raw("Authentication code"))(form3.input(_)(pattern := "[0-9]{6}", autocomplete := "off", required)),
|
||||
form3.action(form3.submit(raw("Disable two-factor authentication"), icon = None))
|
||||
)
|
||||
|
|
|
@ -14,11 +14,11 @@ object username {
|
|||
active = "username"
|
||||
) {
|
||||
div(cls := "account box box-pad")(
|
||||
h1(cls := "text", dataIcon := "*")(trans.changeUsername.frag()),
|
||||
h1(cls := "text", dataIcon := "*")(trans.changeUsername()),
|
||||
st.form(cls := "form3", action := routes.Account.usernameApply, method := "POST")(
|
||||
form3.globalError(form),
|
||||
form3.group(form("username"), trans.username.frag(), help = trans.changeUsernameDescription.frag().some)(form3.input(_)(required)),
|
||||
form3.action(form3.submit(trans.apply.frag()))
|
||||
form3.group(form("username"), trans.username(), help = trans.changeUsernameDescription().some)(form3.input(_)(required)),
|
||||
form3.action(form3.submit(trans.apply()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ object help {
|
|||
private def k(str: String) = raw(s"""<kbd>$str</kbd>""")
|
||||
|
||||
def apply(isStudy: Boolean)(implicit ctx: Context) = frag(
|
||||
h2(trans.keyboardShortcuts.frag()),
|
||||
h2(trans.keyboardShortcuts()),
|
||||
table(
|
||||
tbody(
|
||||
header("Navigate the move tree"),
|
||||
|
@ -49,8 +49,8 @@ object help {
|
|||
tr(
|
||||
td(cls := "mouse", colspan := 2)(
|
||||
ul(
|
||||
li(trans.youCanAlsoScrollOverTheBoardToMoveInTheGame.frag()),
|
||||
li(trans.analysisShapesHowTo.frag())
|
||||
li(trans.youCanAlsoScrollOverTheBoardToMoveInTheGame()),
|
||||
li(trans.analysisShapesHowTo())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package views.html.analyse
|
||||
|
||||
import play.twirl.api.Html
|
||||
|
||||
import bits.dataPanel
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
|
|
|
@ -13,15 +13,15 @@ import controllers.routes
|
|||
object bits {
|
||||
|
||||
def formFields(username: Field, password: Field, emailOption: Option[Field], register: Boolean)(implicit ctx: Context) = frag(
|
||||
form3.group(username, if (register) trans.username.frag() else trans.usernameOrEmail.frag()) { f =>
|
||||
form3.group(username, if (register) trans.username() else trans.usernameOrEmail()) { f =>
|
||||
frag(
|
||||
form3.input(f)(autofocus, required),
|
||||
p(cls := "error exists none")(trans.usernameAlreadyUsed.frag())
|
||||
p(cls := "error exists none")(trans.usernameAlreadyUsed())
|
||||
)
|
||||
},
|
||||
form3.password(password, trans.password.frag()),
|
||||
form3.password(password, trans.password()),
|
||||
emailOption.map { email =>
|
||||
form3.group(email, trans.email.frag())(form3.input(_, typ = "email")(required))
|
||||
form3.group(email, trans.email())(form3.input(_, typ = "email")(required))
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -36,16 +36,16 @@ object bits {
|
|||
ok.map { r =>
|
||||
span(cls := (if (r) "is-green" else "is-red"), dataIcon := (if (r) "E" else "L"))
|
||||
},
|
||||
trans.passwordReset.frag()
|
||||
trans.passwordReset()
|
||||
),
|
||||
st.form(
|
||||
cls := "form3",
|
||||
action := routes.Auth.passwordResetApply,
|
||||
method := "post"
|
||||
)(
|
||||
form3.group(form("email"), trans.email.frag())(form3.input(_, typ = "email")(autofocus)),
|
||||
form3.group(form("email"), trans.email())(form3.input(_, typ = "email")(autofocus)),
|
||||
views.html.base.captcha(form, captcha),
|
||||
form3.action(form3.submit(trans.emailMeALink.frag()))
|
||||
form3.action(form3.submit(trans.emailMeALink()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -55,9 +55,9 @@ object bits {
|
|||
title = trans.passwordReset.txt()
|
||||
) {
|
||||
main(cls := "page-small box box-pad")(
|
||||
h1(cls := "is-green text", dataIcon := "E")(trans.checkYourEmail.frag()),
|
||||
p(trans.weHaveSentYouAnEmailTo.frag(email)),
|
||||
p(trans.ifYouDoNotSeeTheEmailCheckOtherPlaces.frag())
|
||||
h1(cls := "is-green text", dataIcon := "E")(trans.checkYourEmail()),
|
||||
p(trans.weHaveSentYouAnEmailTo(email)),
|
||||
p(trans.ifYouDoNotSeeTheEmailCheckOtherPlaces())
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -74,14 +74,14 @@ object bits {
|
|||
})(
|
||||
userLink(u, withOnline = false),
|
||||
" - ",
|
||||
trans.changePassword.frag()
|
||||
trans.changePassword()
|
||||
),
|
||||
st.form(cls := "form3", action := routes.Auth.passwordResetConfirmApply(token), method := "POST")(
|
||||
form3.hidden(form("token")),
|
||||
form3.passwordModified(form("newPasswd1"), trans.newPassword.frag())(autofocus),
|
||||
form3.password(form("newPasswd2"), trans.newPasswordAgain.frag()),
|
||||
form3.passwordModified(form("newPasswd1"), trans.newPassword())(autofocus),
|
||||
form3.password(form("newPasswd2"), trans.newPasswordAgain()),
|
||||
form3.globalError(form),
|
||||
form3.action(form3.submit(trans.changePassword.frag()))
|
||||
form3.action(form3.submit(trans.changePassword()))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ object login {
|
|||
moreCss = cssTag("auth")
|
||||
) {
|
||||
main(cls := "auth auth-login box box-pad")(
|
||||
h1(trans.signIn.frag()),
|
||||
h1(trans.signIn()),
|
||||
st.form(
|
||||
cls := "form3",
|
||||
action := s"${routes.Auth.authenticate}${referrer.?? { ref => s"?referrer=${java.net.URLEncoder.encode(ref, "US-ASCII")}" }}",
|
||||
|
@ -30,17 +30,17 @@ object login {
|
|||
div(cls := "one-factor")(
|
||||
form3.globalError(form),
|
||||
auth.bits.formFields(form("username"), form("password"), none, register = false),
|
||||
form3.submit(trans.signIn.frag(), icon = none)
|
||||
form3.submit(trans.signIn(), icon = none)
|
||||
),
|
||||
div(cls := "two-factor none")(
|
||||
form3.group(form("token"), raw("Authentication code"), help = Some(twoFactorHelp))(form3.input(_)(autocomplete := "off", pattern := "[0-9]{6}")),
|
||||
p(cls := "error none")("Invalid code."),
|
||||
form3.submit(trans.signIn.frag(), icon = none)
|
||||
form3.submit(trans.signIn(), icon = none)
|
||||
)
|
||||
),
|
||||
div(cls := "alternative")(
|
||||
a(href := routes.Auth.signup())(trans.signUp.frag()),
|
||||
a(href := routes.Auth.passwordReset())(trans.passwordReset.frag())
|
||||
a(href := routes.Auth.signup())(trans.signUp()),
|
||||
a(href := routes.Auth.passwordReset())(trans.passwordReset())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ object signup {
|
|||
csp = defaultCsp.withRecaptcha.some
|
||||
) {
|
||||
main(cls := "auth auth-signup box box-pad")(
|
||||
h1(trans.signUp.frag()),
|
||||
h1(trans.signUp()),
|
||||
st.form(
|
||||
id := "signup_form",
|
||||
cls := "form3",
|
||||
|
@ -35,16 +35,16 @@ object signup {
|
|||
auth.bits.formFields(form("username"), form("password"), form("email").some, register = true),
|
||||
input(id := "signup-fp-input", name := "fp", tpe := "hidden"),
|
||||
div(cls := "form-group text", dataIcon := "")(
|
||||
trans.computersAreNotAllowedToPlay.frag(), br,
|
||||
small(trans.byRegisteringYouAgreeToBeBoundByOur.frag(a(href := routes.Page.tos)(trans.termsOfService.frag())))
|
||||
trans.computersAreNotAllowedToPlay(), br,
|
||||
small(trans.byRegisteringYouAgreeToBeBoundByOur(a(href := routes.Page.tos)(trans.termsOfService())))
|
||||
),
|
||||
if (recaptcha.enabled)
|
||||
button(
|
||||
cls := "g-recaptcha submit button text big",
|
||||
attr("data-sitekey") := recaptcha.key,
|
||||
attr("data-callback") := "signupSubmit"
|
||||
)(trans.signUp.frag())
|
||||
else form3.submit(trans.signUp.frag(), icon = none, klass = "big")
|
||||
)(trans.signUp())
|
||||
else form3.submit(trans.signUp(), icon = none, klass = "big")
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -39,19 +39,19 @@ object captcha {
|
|||
)(div(cls := "cg-board"))
|
||||
),
|
||||
div(cls := "captcha-explanation")(
|
||||
label(cls := "form-label")(trans.colorPlaysCheckmateInOne.frag(
|
||||
(if (captcha.white) trans.white else trans.black).frag()
|
||||
label(cls := "form-label")(trans.colorPlaysCheckmateInOne(
|
||||
(if (captcha.white) trans.white else trans.black)()
|
||||
)),
|
||||
br, br,
|
||||
trans.thisIsAChessCaptcha.frag(),
|
||||
trans.thisIsAChessCaptcha(),
|
||||
br,
|
||||
trans.clickOnTheBoardToMakeYourMove.frag(),
|
||||
trans.clickOnTheBoardToMakeYourMove(),
|
||||
br, br,
|
||||
trans.help.frag(),
|
||||
trans.help(),
|
||||
" ",
|
||||
a(title := trans.viewTheSolution.txt(), target := "_blank", href := url)(url),
|
||||
div(cls := "result success text", dataIcon := "E")(trans.checkmate.frag()),
|
||||
div(cls := "result failure text", dataIcon := "k")(trans.notACheckmate.frag()),
|
||||
div(cls := "result success text", dataIcon := "E")(trans.checkmate()),
|
||||
div(cls := "result failure text", dataIcon := "k")(trans.notACheckmate()),
|
||||
form3.hidden(form("move"))
|
||||
)
|
||||
)
|
||||
|
|
|
@ -190,7 +190,7 @@ object layout {
|
|||
div(cls := "friend_box_title")(
|
||||
strong(cls := "online")("?"),
|
||||
" ",
|
||||
trans.onlineFriends.frag()
|
||||
trans.onlineFriends()
|
||||
),
|
||||
div(cls := "content_wrap")(
|
||||
div(cls := "content list"),
|
||||
|
@ -198,15 +198,15 @@ object layout {
|
|||
"nobody" -> true,
|
||||
"none" -> ctx.onlineFriends.users.nonEmpty
|
||||
))(
|
||||
span(trans.noFriendsOnline.frag()),
|
||||
span(trans.noFriendsOnline()),
|
||||
a(cls := "find button", href := routes.User.opponents)(
|
||||
span(cls := "is3 text", dataIcon := "h")(trans.findFriends.frag())
|
||||
span(cls := "is3 text", dataIcon := "h")(trans.findFriends())
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
},
|
||||
a(id := "reconnecting", cls := "link text", dataIcon := "B")(trans.reconnecting.frag()),
|
||||
a(id := "reconnecting", cls := "link text", dataIcon := "B")(trans.reconnecting()),
|
||||
chessground option jsTag("vendor/chessground.min.js"),
|
||||
ctx.requiresFingerprint option fingerprintTag,
|
||||
if (isProd)
|
||||
|
|
|
@ -16,57 +16,57 @@ object topnav {
|
|||
cls := (if (ctx.blind) "blind" else "hover")
|
||||
)(
|
||||
st.section(
|
||||
linkTitle("/", trans.play.frag()),
|
||||
linkTitle("/", trans.play()),
|
||||
div(role := "group")(
|
||||
if (ctx.noBot) a(href := "/?any#hook")(trans.createAGame.frag())
|
||||
else a(href := "/?any#friend")(trans.playWithAFriend.frag()),
|
||||
if (ctx.noBot) a(href := "/?any#hook")(trans.createAGame())
|
||||
else a(href := "/?any#friend")(trans.playWithAFriend()),
|
||||
ctx.noBot option frag(
|
||||
a(href := routes.Tournament.home())(trans.tournament.frag()),
|
||||
a(href := routes.Simul.home)(trans.simultaneousExhibitions.frag())
|
||||
a(href := routes.Tournament.home())(trans.tournament()),
|
||||
a(href := routes.Simul.home)(trans.simultaneousExhibitions())
|
||||
)
|
||||
)
|
||||
),
|
||||
st.section(
|
||||
linkTitle(routes.Puzzle.home.toString, trans.learnMenu.frag()),
|
||||
linkTitle(routes.Puzzle.home.toString, trans.learnMenu()),
|
||||
div(role := "group")(
|
||||
ctx.noBot option frag(
|
||||
a(href := routes.Learn.index)(trans.chessBasics.frag()),
|
||||
a(href := routes.Puzzle.home)(trans.training.frag()),
|
||||
a(href := routes.Learn.index)(trans.chessBasics()),
|
||||
a(href := routes.Puzzle.home)(trans.training()),
|
||||
a(href := routes.Practice.index)("Practice"),
|
||||
a(href := routes.Coordinate.home)(trans.coordinates.coordinates.frag())
|
||||
a(href := routes.Coordinate.home)(trans.coordinates.coordinates())
|
||||
),
|
||||
a(href := routes.Study.allDefault(1))("Study"),
|
||||
a(href := routes.Coach.allDefault(1))(trans.coaches.frag())
|
||||
a(href := routes.Coach.allDefault(1))(trans.coaches())
|
||||
)
|
||||
),
|
||||
st.section(
|
||||
linkTitle(routes.Tv.index.toString, trans.watch.frag()),
|
||||
linkTitle(routes.Tv.index.toString, trans.watch()),
|
||||
div(role := "group")(
|
||||
a(href := routes.Tv.index)("Lichess TV"),
|
||||
a(href := routes.Tv.games)(trans.currentGames.frag()),
|
||||
a(href := routes.Tv.games)(trans.currentGames()),
|
||||
a(href := routes.Streamer.index())("Streamers"),
|
||||
a(href := routes.Relay.index())("Broadcasts (beta)"),
|
||||
ctx.noBot option a(href := routes.Video.index)(trans.videoLibrary.frag())
|
||||
ctx.noBot option a(href := routes.Video.index)(trans.videoLibrary())
|
||||
)
|
||||
),
|
||||
st.section(
|
||||
linkTitle(routes.User.list.toString, trans.community.frag()),
|
||||
linkTitle(routes.User.list.toString, trans.community()),
|
||||
div(role := "group")(
|
||||
a(href := routes.User.list)(trans.players.frag()),
|
||||
a(href := routes.User.list)(trans.players()),
|
||||
NotForKids(frag(
|
||||
a(href := routes.Team.home())(trans.teams.frag()),
|
||||
a(href := routes.ForumCateg.index)(trans.forum.frag())
|
||||
a(href := routes.Team.home())(trans.teams()),
|
||||
a(href := routes.ForumCateg.index)(trans.forum())
|
||||
))
|
||||
)
|
||||
),
|
||||
st.section(
|
||||
linkTitle(routes.UserAnalysis.index.toString, trans.tools.frag()),
|
||||
linkTitle(routes.UserAnalysis.index.toString, trans.tools()),
|
||||
div(role := "group")(
|
||||
a(href := routes.UserAnalysis.index)(trans.analysis.frag()),
|
||||
a(href := s"${routes.UserAnalysis.index}#explorer")(trans.openingExplorer.frag()),
|
||||
a(href := routes.Editor.index)(trans.boardEditor.frag()),
|
||||
a(href := routes.Importer.importGame)(trans.importGame.frag()),
|
||||
a(href := routes.Search.index())(trans.advancedSearch.frag())
|
||||
a(href := routes.UserAnalysis.index)(trans.analysis()),
|
||||
a(href := s"${routes.UserAnalysis.index}#explorer")(trans.openingExplorer()),
|
||||
a(href := routes.Editor.index)(trans.boardEditor()),
|
||||
a(href := routes.Importer.importGame)(trans.importGame()),
|
||||
a(href := routes.Search.index())(trans.advancedSearch())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package views.html.blog
|
||||
|
||||
import play.api.mvc.RequestHeader
|
||||
|
||||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
import lila.app.ui.ScalatagsTemplate._
|
||||
import lila.common.paginator.Paginator
|
||||
|
||||
import controllers.routes
|
||||
|
||||
object atom {
|
||||
|
||||
def apply(pager: Paginator[io.prismic.Document])(implicit req: RequestHeader) = frag(
|
||||
raw("""<?xml version="1.0" encoding="UTF-8"?>"""),
|
||||
raw("""<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">"""),
|
||||
tag("id")(routes.Blog.index().absoluteURL(true)),
|
||||
link(rel := "alternate", tpe := "text/html", href := routes.Blog.index().absoluteURL(true)),
|
||||
link(rel := "self", tpe := "application/atom+xml", href := routes.Blog.atom().absoluteURL(true)),
|
||||
tag("title")("lichess.org blog"),
|
||||
tag("updated")(pager.currentPageResults.headOption.flatMap(atomDate("blog.date"))),
|
||||
pager.currentPageResults.map { doc =>
|
||||
tag("entry")(
|
||||
tag("id")(routes.Blog.show(doc.id, doc.slug).absoluteURL(true)),
|
||||
tag("published")(atomDate("blog.date")(doc)),
|
||||
tag("updated")(atomDate("blog.date")(doc)),
|
||||
link(rel := "alternate", tpe := "text/html", href := routes.Blog.show(doc.id, doc.slug).absoluteURL(true)),
|
||||
tag("title")(doc.getText("blog.title")),
|
||||
tag("category")(
|
||||
tag("term")(doc.getText("blog.category")),
|
||||
tag("label")(slugify(~doc.getText("blog.category")))
|
||||
),
|
||||
tag("content")(tpe := "html")(
|
||||
doc.getText("blog.shortlede"),
|
||||
"<br>", // yes, scalatags encodes it.
|
||||
doc.getImage("blog.image", "main").map { img =>
|
||||
s"""<img src="${img.url}"/>"""
|
||||
},
|
||||
"<br>",
|
||||
lila.blog.ProtocolFix.add(doc.getStructuredText("blog.body") ?? lila.blog.BlogApi.extract)
|
||||
),
|
||||
tag("tag")("media:thumbnail")(attr("url") := doc.getImage(s"blog.image", "main").map(_.url)),
|
||||
tag("author")(tag("name")(doc.getText("blog.author")))
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
@(pager: Paginator[io.prismic.Document])(implicit req: RequestHeader)
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
|
||||
<id>@routes.Blog.index().absoluteURL(true)</id>
|
||||
<link rel="alternate" type="text/html" href="@routes.Blog.index().absoluteURL(true)"/>
|
||||
<link rel="self" type="application/atom+xml" href="@routes.Blog.atom().absoluteURL(true)"/>
|
||||
<title>lichess.org blog</title>
|
||||
<updated>@pager.currentPageResults.headOption.flatMap(atomDate("blog.date"))</updated>
|
||||
@pager.currentPageResults.map { doc =>
|
||||
<entry>
|
||||
<id>@routes.Blog.show(doc.id, doc.slug).absoluteURL(true)</id>
|
||||
<published>@atomDate("blog.date")(doc)</published>
|
||||
<updated>@atomDate("blog.date")(doc)</updated>
|
||||
<link rel="alternate" type="text/html" href="@routes.Blog.show(doc.id, doc.slug).absoluteURL(true)"/>
|
||||
<title>@doc.getText("blog.title")</title>
|
||||
<category>
|
||||
<term>@doc.getText("blog.category")</term>
|
||||
<label>@slugify(~doc.getText("blog.category"))</label>
|
||||
</category>
|
||||
<content type="html">
|
||||
@doc.getText("blog.shortlede")
|
||||
|
||||
<br />
|
||||
@doc.getImage("blog.image", "main").map { img =>
|
||||
<img src="@img.url"/>
|
||||
}
|
||||
<br />
|
||||
@lila.blog.ProtocolFix.add(doc.getStructuredText("blog.body") ?? lila.blog.BlogApi.extract)
|
||||
</content>
|
||||
<media:thumbnail url="@doc.getImage(s"blog.image", "main").map(_.url)" />
|
||||
<author>
|
||||
<name>@doc.getText("blog.author")</name>
|
||||
</author>
|
||||
</entry>
|
||||
}
|
||||
</feed>
|
||||
|
|
@ -31,8 +31,8 @@ data: ${safeJsonValue(json)}
|
|||
br,
|
||||
span(cls := "clock")(
|
||||
c.daysPerTurn map { days =>
|
||||
if (days == 1) trans.oneDay.frag()
|
||||
else trans.nbDays.pluralSameFrag(days)
|
||||
if (days == 1) trans.oneDay()
|
||||
else trans.nbDays.pluralSame(days)
|
||||
} getOrElse shortClockName(c.clock.map(_.config))
|
||||
)
|
||||
)
|
||||
|
|
|
@ -13,7 +13,7 @@ object mine {
|
|||
|
||||
val cancelForm =
|
||||
form(method := "post", action := routes.Challenge.cancel(c.id), cls := "cancel xhr")(
|
||||
button(tpe := "submit", cls := "button button-red text", dataIcon := "L")(trans.cancel.frag())
|
||||
button(tpe := "submit", cls := "button button-red text", dataIcon := "L")(trans.cancel())
|
||||
)
|
||||
|
||||
views.html.base.layout(
|
||||
|
@ -25,13 +25,13 @@ object mine {
|
|||
main(cls := "page-small challenge-page box box-pad")(
|
||||
c.status match {
|
||||
case Status.Created | Status.Offline => div(id := "ping-challenge")(
|
||||
h1(trans.challengeToPlay.frag()),
|
||||
h1(trans.challengeToPlay()),
|
||||
bits.details(c),
|
||||
c.destUserId.map { destId =>
|
||||
div(cls := "waiting")(
|
||||
userIdLink(destId.some, cssClass = "target".some),
|
||||
spinner,
|
||||
p(trans.waitingForOpponent.frag())
|
||||
p(trans.waitingForOpponent())
|
||||
)
|
||||
} getOrElse div(cls := "invite")(
|
||||
div(
|
||||
|
@ -46,7 +46,7 @@ object mine {
|
|||
),
|
||||
button(title := "Copy URL", cls := "copy button", dataRel := "challenge-id", dataIcon := "\"")
|
||||
),
|
||||
p(trans.theFirstPersonToComeOnThisUrlWillPlayWithYou.frag())
|
||||
p(trans.theFirstPersonToComeOnThisUrlWillPlayWithYou())
|
||||
),
|
||||
ctx.isAuth option div(
|
||||
p("Or invite a lichess user:"),
|
||||
|
@ -67,19 +67,19 @@ object mine {
|
|||
case Status.Declined => div(cls := "follow-up")(
|
||||
h1("Challenge declined"),
|
||||
bits.details(c),
|
||||
a(cls := "button button-fat", href := routes.Lobby.home())(trans.newOpponent.frag())
|
||||
a(cls := "button button-fat", href := routes.Lobby.home())(trans.newOpponent())
|
||||
)
|
||||
case Status.Accepted => div(cls := "follow-up")(
|
||||
h1("Challenge accepted!"),
|
||||
bits.details(c),
|
||||
a(id := "challenge-redirect", href := routes.Round.watcher(c.id, "white"), cls := "button-fat")(
|
||||
trans.joinTheGame.frag()
|
||||
trans.joinTheGame()
|
||||
)
|
||||
)
|
||||
case Status.Canceled => div(cls := "follow-up")(
|
||||
h1("Challenge canceled."),
|
||||
bits.details(c),
|
||||
a(cls := "button button-fat", href := routes.Lobby.home())(trans.newOpponent.frag())
|
||||
a(cls := "button button-fat", href := routes.Lobby.home())(trans.newOpponent())
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -34,9 +34,9 @@ object theirs {
|
|||
},
|
||||
if (!c.mode.rated || ctx.isAuth) frag(
|
||||
(c.mode.rated && c.unlimited) option
|
||||
badTag(trans.bewareTheGameIsRatedButHasNoClock.frag()),
|
||||
badTag(trans.bewareTheGameIsRatedButHasNoClock()),
|
||||
form(cls := "accept", action := routes.Challenge.accept(c.id), method := "post")(
|
||||
button(tpe := "submit", cls := "text button button-fat", dataIcon := "G")(trans.joinTheGame.frag())
|
||||
button(tpe := "submit", cls := "text button button-fat", dataIcon := "G")(trans.joinTheGame())
|
||||
)
|
||||
)
|
||||
else frag(
|
||||
|
@ -45,7 +45,7 @@ object theirs {
|
|||
p("This game is rated"),
|
||||
p(
|
||||
"You must ",
|
||||
a(cls := "button", href := s"${routes.Auth.login}?referrer=${routes.Round.watcher(c.id, "white")}")(trans.signIn.frag()),
|
||||
a(cls := "button", href := s"${routes.Auth.login}?referrer=${routes.Round.watcher(c.id, "white")}")(trans.signIn()),
|
||||
" to join it."
|
||||
)
|
||||
)
|
||||
|
@ -54,19 +54,19 @@ object theirs {
|
|||
case Status.Declined => div(cls := "follow-up")(
|
||||
h1("Challenge declined"),
|
||||
bits.details(c),
|
||||
a(cls := "button button-fat", href := routes.Lobby.home())(trans.newOpponent.frag())
|
||||
a(cls := "button button-fat", href := routes.Lobby.home())(trans.newOpponent())
|
||||
)
|
||||
case Status.Accepted => div(cls := "follow-up")(
|
||||
h1("Challenge accepted!"),
|
||||
bits.details(c),
|
||||
a(id := "challenge-redirect", href := routes.Round.watcher(c.id, "white"), cls := "button button-fat")(
|
||||
trans.joinTheGame.frag()
|
||||
trans.joinTheGame()
|
||||
)
|
||||
)
|
||||
case Status.Canceled => div(cls := "follow-up")(
|
||||
h1("Challenge canceled."),
|
||||
bits.details(c),
|
||||
a(cls := "button button-fat", href := routes.Lobby.home())(trans.newOpponent.frag())
|
||||
a(cls := "button button-fat", href := routes.Lobby.home())(trans.newOpponent())
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -47,7 +47,7 @@ object review {
|
|||
)(
|
||||
mine.map(_.text)
|
||||
),
|
||||
button(tpe := "submit", cls := "button")(trans.apply.frag())
|
||||
button(tpe := "submit", cls := "button")(trans.apply())
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -35,14 +35,14 @@ object coordinate {
|
|||
)(
|
||||
div(cls := "coord-trainer__side")(
|
||||
div(cls := "box")(
|
||||
h1(trans.coordinates.coordinates.frag()),
|
||||
h1(trans.coordinates.coordinates()),
|
||||
if (ctx.isAuth) scoreOption.map { score =>
|
||||
div(cls := "scores")(scoreCharts(score))
|
||||
}
|
||||
else div(cls := "register")(
|
||||
p(trans.toTrackYourProgress.frag()),
|
||||
p(trans.toTrackYourProgress()),
|
||||
p(cls := "signup")(
|
||||
a(cls := "button", href := routes.Auth.signup)(trans.signUp.frag())
|
||||
a(cls := "button", href := routes.Auth.signup)(trans.signUp())
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -71,15 +71,15 @@ object coordinate {
|
|||
),
|
||||
div(cls := "coord-trainer__table")(
|
||||
div(cls := "explanation")(
|
||||
p(trans.coordinates.knowingTheChessBoard.frag()),
|
||||
p(trans.coordinates.knowingTheChessBoard()),
|
||||
ul(
|
||||
li(trans.coordinates.mostChessCourses.frag()),
|
||||
li(trans.coordinates.talkToYourChessFriends.frag()),
|
||||
li(trans.coordinates.youCanAnalyseAGameMoreEffectively.frag())
|
||||
li(trans.coordinates.mostChessCourses()),
|
||||
li(trans.coordinates.talkToYourChessFriends()),
|
||||
li(trans.coordinates.youCanAnalyseAGameMoreEffectively())
|
||||
),
|
||||
p(trans.coordinates.aSquareNameAppears.frag())
|
||||
p(trans.coordinates.aSquareNameAppears())
|
||||
),
|
||||
button(cls := "start button button-fat")(trans.coordinates.startTraining.frag())
|
||||
button(cls := "start button button-fat")(trans.coordinates.startTraining())
|
||||
),
|
||||
div(cls := "coord-trainer__score")(0),
|
||||
div(cls := "coord-trainer__progress")(div(cls := "progress_bar"))
|
||||
|
|
|
@ -46,7 +46,7 @@ object event {
|
|||
},
|
||||
if (e.isFinished) p(cls := "desc")("The event is finished.")
|
||||
else {
|
||||
if (e.isNow) a(href := e.url, cls := "button button-fat")(trans.eventInProgress.frag())
|
||||
if (e.isNow) a(href := e.url, cls := "button button-fat")(trans.eventInProgress())
|
||||
else ul(cls := "countdown", dataSeconds := ~e.secondsToStart)(
|
||||
List("Days", "Hours", "Minutes", "Seconds") map { t =>
|
||||
li(span(cls := t.toLowerCase), t)
|
||||
|
@ -113,7 +113,7 @@ object event {
|
|||
form3.checkbox(form("enabled"), raw("Enabled"), help = raw("Display the event").some, half = true),
|
||||
form3.group(form("homepageHours"), raw("Hours on homepage (0 to 24)"), half = true, help = raw("Ask on slack first!").some)(form3.input(_, typ = "number"))
|
||||
),
|
||||
form3.action(form3.submit(trans.apply.frag()))
|
||||
form3.action(form3.submit(trans.apply()))
|
||||
)
|
||||
|
||||
private def layout(title: String, css: String = "mod.misc")(body: Frag)(implicit ctx: Context) =
|
||||
|
|
|
@ -41,7 +41,7 @@ object categ {
|
|||
|
||||
val newTopicButton = canWrite option
|
||||
a(href := routes.ForumTopic.form(categ.slug), cls := "button button-empty button-green text", dataIcon := "m")(
|
||||
trans.createANewTopic.frag()
|
||||
trans.createANewTopic()
|
||||
)
|
||||
def showTopic(sticky: Boolean)(topic: lila.forum.TopicView) = tr(cls := List("sticky" -> sticky))(
|
||||
td(cls := "subject")(
|
||||
|
@ -89,9 +89,9 @@ object categ {
|
|||
thead(
|
||||
tr(
|
||||
th,
|
||||
th(cls := "right")(trans.views.frag()),
|
||||
th(cls := "right")(trans.replies.frag()),
|
||||
th(trans.lastPost.frag())
|
||||
th(cls := "right")(trans.views()),
|
||||
th(cls := "right")(trans.replies()),
|
||||
th(trans.lastPost())
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
|
@ -109,9 +109,9 @@ object categ {
|
|||
thead(
|
||||
tr(
|
||||
th,
|
||||
th(cls := "right")(trans.topics.frag()),
|
||||
th(cls := "right")(trans.posts.frag()),
|
||||
th(trans.lastPost.frag())
|
||||
th(cls := "right")(trans.topics()),
|
||||
th(cls := "right")(trans.posts()),
|
||||
th(trans.lastPost())
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
|
@ -130,7 +130,7 @@ object categ {
|
|||
momentFromNow(post.createdAt)
|
||||
),
|
||||
br,
|
||||
trans.by.frag(authorName(post))
|
||||
trans.by(authorName(post))
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -72,9 +72,9 @@ object post {
|
|||
)(post.text),
|
||||
div(cls := "edit-buttons")(
|
||||
a(cls := "edit-post-cancel", href := routes.ForumPost.redirect(post.id), style := "margin-left:20px")(
|
||||
trans.cancel.frag()
|
||||
trans.cancel()
|
||||
),
|
||||
button(`type` := "submit", cls := "button")(trans.apply.frag())
|
||||
button(`type` := "submit", cls := "button")(trans.apply())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -41,14 +41,14 @@ object topic {
|
|||
),
|
||||
|
||||
st.form(cls := "form3", action := routes.ForumTopic.create(categ.slug), method := "POST")(
|
||||
form3.group(form("name"), trans.subject.frag())(form3.input(_)(autofocus)),
|
||||
form3.group(form("post")("text"), trans.message.frag())(form3.textarea(_, klass = "post-text-area")(rows := 10)),
|
||||
form3.group(form("name"), trans.subject())(form3.input(_)(autofocus)),
|
||||
form3.group(form("post")("text"), trans.message())(form3.textarea(_, klass = "post-text-area")(rows := 10)),
|
||||
views.html.base.captcha(form("post"), captcha),
|
||||
form3.actions(
|
||||
a(href := routes.ForumCateg.show(categ.slug))(trans.cancel.frag()),
|
||||
a(href := routes.ForumCateg.show(categ.slug))(trans.cancel()),
|
||||
isGranted(_.PublicMod) option
|
||||
form3.submit(frag("Create as mod"), nameValue = (form("post")("modIcon").name, "true").some, icon = "".some),
|
||||
form3.submit(trans.createTheTopic.frag())
|
||||
form3.submit(trans.createTheTopic())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -104,8 +104,8 @@ object topic {
|
|||
else if (topic.isOld)
|
||||
p("This topic has been archived and can no longer be replied to.")
|
||||
else if (formWithCaptcha.isDefined)
|
||||
h2(id := "reply")(trans.replyToThisTopic.frag())
|
||||
else if (topic.closed) p(trans.thisTopicIsNowClosed.frag())
|
||||
h2(id := "reply")(trans.replyToThisTopic())
|
||||
else if (topic.closed) p(trans.thisTopicIsNowClosed())
|
||||
else categ.team.filterNot(myTeam).map { teamId =>
|
||||
p(
|
||||
a(href := routes.Team.show(teamId)),
|
||||
|
@ -143,15 +143,15 @@ object topic {
|
|||
method := "POST",
|
||||
novalidate
|
||||
)(
|
||||
form3.group(form("text"), trans.message.frag()) { f =>
|
||||
form3.group(form("text"), trans.message()) { f =>
|
||||
form3.textarea(f, klass = "post-text-area")(rows := 10, bits.dataTopic := topic.id)
|
||||
},
|
||||
views.html.base.captcha(form, captcha),
|
||||
form3.actions(
|
||||
a(href := routes.ForumCateg.show(categ.slug))(trans.cancel.frag()),
|
||||
a(href := routes.ForumCateg.show(categ.slug))(trans.cancel()),
|
||||
isGranted(_.PublicMod) option
|
||||
form3.submit(frag("Reply as mod"), nameValue = (form("modIcon").name, "true").some, icon = "".some),
|
||||
form3.submit(trans.reply.frag())
|
||||
form3.submit(trans.reply())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ object bits {
|
|||
ctxOption flatMap { implicit ctx =>
|
||||
pov.game.daysPerTurn map { days =>
|
||||
span(cls := "vstext__clock")(
|
||||
if (days == 1) trans.oneDay.frag() else trans.nbDays.pluralSame(days)
|
||||
if (days == 1) trans.oneDay() else trans.nbDays.pluralSame(days)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,12 +26,12 @@ object importGame {
|
|||
h1(trans.importGame()),
|
||||
p(cls := "explanation")(trans.importGameExplanation()),
|
||||
st.form(cls := "form3 import", action := routes.Importer.sendGame(), method := "post")(
|
||||
form3.group(form("pgn"), trans.pasteThePgnStringHere.frag())(form3.textarea(_)()),
|
||||
form3.group(form("pgn"), trans.pasteThePgnStringHere())(form3.textarea(_)()),
|
||||
form3.group(form("pgnFile"), raw("Or upload a PGN file"), klass = "upload") { f =>
|
||||
form3.file.pgn(f.name)
|
||||
},
|
||||
form3.checkbox(form("analyse"), trans.requestAComputerAnalysis.frag(), help = Some(analyseHelp), disabled = ctx.isAnon),
|
||||
form3.action(form3.submit(trans.importGame.frag(), "/".some))
|
||||
form3.checkbox(form("analyse"), trans.requestAComputerAnalysis(), help = Some(analyseHelp), disabled = ctx.isAnon),
|
||||
form3.action(form3.submit(trans.importGame(), "/".some))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -90,7 +90,7 @@ object side {
|
|||
game.winner.map { winner =>
|
||||
frag(
|
||||
separator,
|
||||
winner.color.fold(trans.whiteIsVictorious, trans.blackIsVictorious).frag()
|
||||
winner.color.fold(trans.whiteIsVictorious, trans.blackIsVictorious)()
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -64,7 +64,7 @@ object irwin {
|
|||
)
|
||||
}
|
||||
|
||||
def report(report: lila.irwin.IrwinReport.WithPovs)(implicit ctx: Context) =
|
||||
def report(report: lila.irwin.IrwinReport.WithPovs)(implicit ctx: Context): Frag =
|
||||
div(id := "mz_irwin")(
|
||||
header(
|
||||
a(cls := "title", href := routes.Irwin.dashboard)(
|
||||
|
|
|
@ -21,8 +21,8 @@ object bits {
|
|||
)(implicit ctx: Context) = frag(
|
||||
div(cls := "lobby__leaderboard lobby__box")(
|
||||
div(cls := "lobby__box__top")(
|
||||
span(cls := "title text", dataIcon := "C")(trans.leaderboard.frag()),
|
||||
a(cls := "more", href := routes.User.list)(trans.more.frag(), " »")
|
||||
span(cls := "title text", dataIcon := "C")(trans.leaderboard()),
|
||||
a(cls := "more", href := routes.User.list)(trans.more(), " »")
|
||||
),
|
||||
div(cls := "lobby__box__content")(
|
||||
table(tbody(
|
||||
|
@ -40,8 +40,8 @@ object bits {
|
|||
),
|
||||
div(cls := "lobby__winners lobby__box")(
|
||||
div(cls := "lobby__box__top")(
|
||||
span(cls := "title text", dataIcon := "g")(trans.tournamentWinners.frag()),
|
||||
a(cls := "more", href := routes.Tournament.leaderboard)(trans.more.frag(), " »")
|
||||
span(cls := "title text", dataIcon := "g")(trans.tournamentWinners()),
|
||||
a(cls := "more", href := routes.Tournament.leaderboard)(trans.more(), " »")
|
||||
),
|
||||
div(cls := "lobby__box__content")(
|
||||
table(tbody(
|
||||
|
@ -56,8 +56,8 @@ object bits {
|
|||
),
|
||||
div(cls := "lobby__tournaments lobby__box")(
|
||||
div(cls := "lobby__box__top")(
|
||||
span(cls := "title text", dataIcon := "g")(trans.openTournaments.frag()),
|
||||
a(cls := "more", href := routes.Tournament.home())(trans.more.frag(), " »")
|
||||
span(cls := "title text", dataIcon := "g")(trans.openTournaments()),
|
||||
a(cls := "more", href := routes.Tournament.home())(trans.more(), " »")
|
||||
),
|
||||
div(id := "enterable_tournaments", cls := "enterable_list lobby__box__content")(
|
||||
views.html.tournament.bits.enterable(tours)
|
||||
|
@ -65,8 +65,8 @@ object bits {
|
|||
),
|
||||
div(cls := "lobby__simuls lobby__box")(
|
||||
div(cls := "lobby__box__top")(
|
||||
span(cls := "title text", dataIcon := "f")(trans.simultaneousExhibitions.frag()),
|
||||
a(cls := "more", href := routes.Simul.home())(trans.more.frag(), " »")
|
||||
span(cls := "title text", dataIcon := "f")(trans.simultaneousExhibitions()),
|
||||
a(cls := "more", href := routes.Simul.home())(trans.more(), " »")
|
||||
),
|
||||
div(id := "enterable_simuls", cls := "enterable_list lobby__box__content")(
|
||||
views.html.simul.bits.allCreated(simuls)
|
||||
|
@ -77,8 +77,8 @@ object bits {
|
|||
def lastPosts(posts: List[lila.blog.MiniPost])(implicit ctx: Context): Option[Frag] = posts.nonEmpty option
|
||||
div(cls := "lobby__blog lobby__box")(
|
||||
div(cls := "lobby__box__top")(
|
||||
span(cls := "title text", dataIcon := "6")(trans.latestUpdates.frag()),
|
||||
a(cls := "more", href := routes.Blog.index())(trans.more.frag(), " »")
|
||||
span(cls := "title text", dataIcon := "6")(trans.latestUpdates()),
|
||||
a(cls := "more", href := routes.Blog.index())(trans.more(), " »")
|
||||
),
|
||||
div(cls := "lobby__box__content")(
|
||||
posts map { post =>
|
||||
|
|
|
@ -59,20 +59,20 @@ object home {
|
|||
a(href := routes.Setup.hookForm, cls := List(
|
||||
"button button-metal config_hook" -> true,
|
||||
"disabled" -> (playban.isDefined || currentGame.isDefined || ctx.isBot)
|
||||
), trans.createAGame.frag()),
|
||||
), trans.createAGame()),
|
||||
a(href := routes.Setup.friendForm(none), cls := List(
|
||||
"button button-metal config_friend" -> true,
|
||||
"disabled" -> currentGame.isDefined
|
||||
), trans.playWithAFriend.frag()),
|
||||
), trans.playWithAFriend()),
|
||||
a(href := routes.Setup.aiForm, cls := List(
|
||||
"button button-metal config_ai" -> true,
|
||||
"disabled" -> currentGame.isDefined
|
||||
), trans.playWithTheMachine.frag())
|
||||
), trans.playWithTheMachine())
|
||||
),
|
||||
div(cls := "lobby__counters")(
|
||||
a(id := "nb_connected_players", href := ctx.noBlind.option(routes.User.list.toString))(trans.nbPlayers.frag(nbPlayersPlaceholder)),
|
||||
a(id := "nb_connected_players", href := ctx.noBlind.option(routes.User.list.toString))(trans.nbPlayers(nbPlayersPlaceholder)),
|
||||
a(id := "nb_games_in_play", href := ctx.noBlind.option(routes.Tv.games.toString))(
|
||||
trans.nbGamesInPlay.pluralFrag(nbRounds, strong(nbRounds))
|
||||
trans.nbGamesInPlay.plural(nbRounds, strong(nbRounds))
|
||||
)
|
||||
)
|
||||
),
|
||||
|
@ -92,12 +92,12 @@ object home {
|
|||
div(cls := "timeline", dataHref := routes.Timeline.home)(
|
||||
views.html.timeline entries userTimeline,
|
||||
// userTimeline.size >= 8 option
|
||||
a(cls := "more", href := routes.Timeline.home)(trans.more.frag(), " »")
|
||||
a(cls := "more", href := routes.Timeline.home)(trans.more(), " »")
|
||||
)
|
||||
} getOrElse div(cls := "about-side")(
|
||||
trans.xIsAFreeYLibreOpenSourceChessServer.frag("Lichess", a(cls := "blue", href := routes.Plan.features)(trans.really.txt())),
|
||||
trans.xIsAFreeYLibreOpenSourceChessServer("Lichess", a(cls := "blue", href := routes.Plan.features)(trans.really.txt())),
|
||||
" ",
|
||||
a(cls := "blue", href := "/about")(trans.aboutX.frag("lichess.org"), "...")
|
||||
a(cls := "blue", href := "/about")(trans.aboutX("lichess.org"), "...")
|
||||
)
|
||||
),
|
||||
featured map { g =>
|
||||
|
@ -110,7 +110,7 @@ object home {
|
|||
div(cls := "lobby__puzzle", title := trans.clickToSolve.txt())(
|
||||
raw(p.html),
|
||||
div(cls := "vstext")(
|
||||
trans.puzzleOfTheDay.frag(),
|
||||
trans.puzzleOfTheDay(),
|
||||
br,
|
||||
p.color.fold(trans.whitePlays, trans.blackPlays)()
|
||||
)
|
||||
|
@ -119,8 +119,8 @@ object home {
|
|||
ctx.noBot option bits.underboards(tours, simuls, leaderboard, tournamentWinners),
|
||||
ctx.noKid option div(cls := "lobby__forum lobby__box")(
|
||||
div(cls := "lobby__box__top")(
|
||||
span(cls := "title text", dataIcon := "d")(trans.latestForumPosts.frag()),
|
||||
a(cls := "more", href := routes.ForumCateg.index)(trans.more.frag(), " »")
|
||||
span(cls := "title text", dataIcon := "d")(trans.latestForumPosts()),
|
||||
a(cls := "more", href := routes.ForumCateg.index)(trans.more(), " »")
|
||||
),
|
||||
div(cls := "lobby__box__content")(
|
||||
views.html.forum.post recent forumRecent
|
||||
|
@ -132,32 +132,32 @@ object home {
|
|||
iconTag(patronIconChar),
|
||||
span(cls := "lobby__support__text")(
|
||||
strong("Lichess Patron"),
|
||||
span(trans.directlySupportLichess.frag())
|
||||
span(trans.directlySupportLichess())
|
||||
)
|
||||
),
|
||||
a(href := routes.Page.swag)(
|
||||
iconTag(""),
|
||||
span(cls := "lobby__support__text")(
|
||||
strong("Swag Store"),
|
||||
span(trans.playChessInStyle.frag())
|
||||
span(trans.playChessInStyle())
|
||||
)
|
||||
)
|
||||
),
|
||||
div(cls := "lobby__about")(
|
||||
a(href := "/about")(trans.aboutX.frag("lichess.org")),
|
||||
a(href := "/about")(trans.aboutX("lichess.org")),
|
||||
a(href := "/faq")("FAQ"),
|
||||
a(href := "/contact")(trans.contact.frag()),
|
||||
a(href := "/contact")(trans.contact()),
|
||||
ctx.noKid option frag(
|
||||
a(href := "/mobile")(trans.mobileApp.frag()),
|
||||
a(href := "/developers")(trans.webmasters.frag()),
|
||||
a(href := "/help/contribute")(trans.contribute.frag()),
|
||||
a(href := "/patron")(trans.donate.frag())
|
||||
a(href := "/mobile")(trans.mobileApp()),
|
||||
a(href := "/developers")(trans.webmasters()),
|
||||
a(href := "/help/contribute")(trans.contribute()),
|
||||
a(href := "/patron")(trans.donate())
|
||||
),
|
||||
a(href := "/thanks")(trans.thankYou.frag()),
|
||||
a(href := routes.Page.tos)(trans.termsOfService.frag()),
|
||||
a(href := routes.Page.privacy)(trans.privacy.frag()),
|
||||
a(href := "https://database.lichess.org/")(trans.database.frag()),
|
||||
a(href := "https://github.com/ornicar/lila")(trans.sourceCode.frag())
|
||||
a(href := "/thanks")(trans.thankYou()),
|
||||
a(href := routes.Page.tos)(trans.termsOfService()),
|
||||
a(href := routes.Page.privacy)(trans.privacy()),
|
||||
a(href := "https://database.lichess.org/")(trans.database()),
|
||||
a(href := "https://github.com/ornicar/lila")(trans.sourceCode())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ object form {
|
|||
moreJs = jsTag("message.js")
|
||||
) {
|
||||
main(cls := "message-new box box-pad")(
|
||||
h1(trans.composeMessage.frag()),
|
||||
h1(trans.composeMessage()),
|
||||
reqUser.ifFalse(canMessage).map { u =>
|
||||
frag(
|
||||
br, br, hr, br,
|
||||
|
@ -42,7 +42,7 @@ object form {
|
|||
action := s"${routes.Message.create()}${reqUser.??(u => "?username=" + u.username)}",
|
||||
method := "post"
|
||||
)(
|
||||
form3.group(form("username"), trans.recipient.frag()) { f =>
|
||||
form3.group(form("username"), trans.recipient()) { f =>
|
||||
reqUser map { user =>
|
||||
frag(
|
||||
userLink(user),
|
||||
|
@ -63,7 +63,7 @@ object form {
|
|||
form3.group(form("preset"), frag("Preset")) { form3.select(_, Nil) },
|
||||
embedJsUnsafe(s"""lichess_mod_presets=${safeJsonValue(lila.message.ModPreset.asJson)}""")
|
||||
),
|
||||
form3.group(form("subject"), trans.subject.frag()) { f =>
|
||||
form3.group(form("subject"), trans.subject()) { f =>
|
||||
input(
|
||||
cls := "form-control",
|
||||
required,
|
||||
|
@ -79,8 +79,8 @@ object form {
|
|||
form3.textarea(f)(required)
|
||||
},
|
||||
form3.actions(
|
||||
a(cls := "cancel", href := routes.Message.inbox())(trans.cancel.frag()),
|
||||
button(cls := "button text", dataIcon := "E", tpe := "submit")(trans.send.frag())
|
||||
a(cls := "cancel", href := routes.Message.inbox())(trans.cancel()),
|
||||
button(cls := "button text", dataIcon := "E", tpe := "submit")(trans.send())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ object inbox {
|
|||
) {
|
||||
main(cls := "message-list box")(
|
||||
div(cls := "box__top")(
|
||||
h1(trans.inbox.frag()),
|
||||
h1(trans.inbox()),
|
||||
threads.nbResults > 0 option div(cls := "box__top__actions")(
|
||||
select(cls := "select")(
|
||||
option(value := "")("Select"),
|
||||
|
@ -32,7 +32,7 @@ object inbox {
|
|||
option(value := "read")("Mark as read"),
|
||||
option(value := "delete")("Delete")
|
||||
),
|
||||
a(href := routes.Message.form, cls := "button button-green text", dataIcon := "m")(trans.composeMessage.frag())
|
||||
a(href := routes.Message.form, cls := "button button-green text", dataIcon := "m")(trans.composeMessage())
|
||||
)
|
||||
),
|
||||
table(cls := "slist slist-pad")(
|
||||
|
@ -51,7 +51,7 @@ object inbox {
|
|||
)
|
||||
}
|
||||
)
|
||||
else tbody(tr(td(trans.noNewMessages.frag())))
|
||||
else tbody(tr(td(trans.noNewMessages())))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -73,8 +73,8 @@ object thread {
|
|||
errMsg(form("text"))
|
||||
),
|
||||
div(cls := "actions")(
|
||||
a(cls := "cancel", href := routes.Message.inbox(1))(trans.cancel.frag()),
|
||||
button(cls := "button text", dataIcon := "E", tpe := "submit")(trans.send.frag())
|
||||
a(cls := "cancel", href := routes.Message.inbox(1))(trans.cancel()),
|
||||
button(cls := "button text", dataIcon := "E", tpe := "submit")(trans.send())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ object mobile {
|
|||
) {
|
||||
main(
|
||||
div(cls := "mobile page-small box box-pad")(
|
||||
h1(trans.playChessEverywhere.frag()),
|
||||
h1(trans.playChessEverywhere()),
|
||||
div(cls := "sides")(
|
||||
div(cls := "left-side")(
|
||||
div(cls := "stores")(
|
||||
|
@ -24,26 +24,26 @@ object mobile {
|
|||
div(cls := "apk")(
|
||||
raw(~apkDoc.getHtml("doc.content", resolver))
|
||||
),
|
||||
h2(trans.asFreeAsLichess.frag()),
|
||||
h2(trans.asFreeAsLichess()),
|
||||
ul(cls := "block")(
|
||||
li(trans.builtForTheLoveOfChessNotMoney.frag()),
|
||||
li(trans.everybodyGetsAllFeaturesForFree.frag()),
|
||||
li(trans.zeroAdvertisement.frag()),
|
||||
li(trans.builtForTheLoveOfChessNotMoney()),
|
||||
li(trans.everybodyGetsAllFeaturesForFree()),
|
||||
li(trans.zeroAdvertisement()),
|
||||
li("Entirely ", a(href := "https://github.com/veloce/lichobile")("Open Source"))
|
||||
),
|
||||
h2(trans.fullFeatured.frag()),
|
||||
h2(trans.fullFeatured()),
|
||||
ul(cls := "block")(
|
||||
li(trans.phoneAndTablet.frag()),
|
||||
li(trans.bulletBlitzClassical.frag()),
|
||||
li(trans.correspondenceChess.frag()),
|
||||
li(trans.onlineAndOfflinePlay.frag()),
|
||||
li(trans.tournaments.frag()),
|
||||
li(trans.puzzles.frag()),
|
||||
li(trans.gameAnalysis.frag()),
|
||||
li(trans.boardEditor.frag()),
|
||||
li(trans.phoneAndTablet()),
|
||||
li(trans.bulletBlitzClassical()),
|
||||
li(trans.correspondenceChess()),
|
||||
li(trans.onlineAndOfflinePlay()),
|
||||
li(trans.tournaments()),
|
||||
li(trans.puzzles()),
|
||||
li(trans.gameAnalysis()),
|
||||
li(trans.boardEditor()),
|
||||
li("Lichess TV"),
|
||||
li(trans.followAndChallengeFriends.frag()),
|
||||
li(trans.availableInNbLanguages.pluralSameFrag(80))
|
||||
li(trans.followAndChallengeFriends()),
|
||||
li(trans.availableInNbLanguages.pluralSame(80))
|
||||
)
|
||||
),
|
||||
div(cls := "right-side")(
|
||||
|
|
|
@ -61,7 +61,7 @@ object form {
|
|||
),
|
||||
form3.actions(
|
||||
a(href := routes.OAuthApp.index)("Cancel"),
|
||||
form3.submit(trans.apply.frag())
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ object create {
|
|||
),
|
||||
form3.actions(
|
||||
a(href := routes.OAuthToken.index)("Cancel"),
|
||||
form3.submit(trans.apply.frag())
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -32,8 +32,8 @@ object embed {
|
|||
div(id := "daily-puzzle", cls := "embedded", title := trans.clickToSolve.txt())(
|
||||
raw(daily.html),
|
||||
div(cls := "vstext", style := "text-align: center; justify-content: center")(
|
||||
trans.puzzleOfTheDay.frag(), br,
|
||||
daily.color.fold(trans.whitePlays, trans.blackPlays).frag()
|
||||
trans.puzzleOfTheDay(), br,
|
||||
daily.color.fold(trans.whitePlays, trans.blackPlays)()
|
||||
)
|
||||
),
|
||||
jQueryTag,
|
||||
|
|
|
@ -18,9 +18,9 @@ object bits {
|
|||
div(cls := "box__top")(
|
||||
h1(userLink(u, withOnline = false)),
|
||||
div(cls := "actions")(
|
||||
trans.nbFollowers.pluralSameFrag(pag.nbResults),
|
||||
trans.nbFollowers.pluralSame(pag.nbResults),
|
||||
" ", amp, " ",
|
||||
a(href := routes.Relation.following(u.username))(trans.nbFollowing.pluralSameFrag(nbFollowing))
|
||||
a(href := routes.Relation.following(u.username))(trans.nbFollowing.pluralSame(nbFollowing))
|
||||
)
|
||||
),
|
||||
pagTable(pag, routes.Relation.followers(u.username))
|
||||
|
@ -31,9 +31,9 @@ object bits {
|
|||
div(cls := "box__top")(
|
||||
h1(userLink(u, withOnline = false)),
|
||||
div(cls := "actions")(
|
||||
trans.nbFollowing.pluralSameFrag(pag.nbResults),
|
||||
trans.nbFollowing.pluralSame(pag.nbResults),
|
||||
" ", amp, " ",
|
||||
a(href := routes.Relation.followers(u.username))(trans.nbFollowers.pluralSameFrag(nbFollowers))
|
||||
a(href := routes.Relation.followers(u.username))(trans.nbFollowers.pluralSame(nbFollowers))
|
||||
)
|
||||
),
|
||||
pagTable(pag, routes.Relation.following(u.username))
|
||||
|
@ -44,7 +44,7 @@ object bits {
|
|||
div(cls := "box__top")(
|
||||
h1(userLink(u, withOnline = false)),
|
||||
div(cls := "actions")(
|
||||
trans.blocks.pluralSameFrag(pag.nbResults)
|
||||
trans.blocks.pluralSame(pag.nbResults)
|
||||
)
|
||||
),
|
||||
pagTable(pag, routes.Relation.blocks())
|
||||
|
@ -67,7 +67,7 @@ object bits {
|
|||
tr(cls := "paginated")(
|
||||
td(userLink(r.user)),
|
||||
td(showBestPerf(r.user)),
|
||||
td(trans.nbGames.pluralSameFrag(r.user.count.game)),
|
||||
td(trans.nbGames.pluralSame(r.user.count.game)),
|
||||
td(actions(r.user.id, relation = r.relation, followable = r.followable, blocked = false))
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,19 +18,19 @@ object mini {
|
|||
cls := "btn-rack__btn relation-button text",
|
||||
dataIcon := "h",
|
||||
href := s"${routes.Relation.follow(userId)}?mini=1"
|
||||
)(trans.follow.frag())
|
||||
)(trans.follow())
|
||||
case Some(true) => a(
|
||||
cls := "btn-rack__btn relation-button text",
|
||||
title := trans.unfollow.txt(),
|
||||
href := s"${routes.Relation.unfollow(userId)}?mini=1",
|
||||
dataIcon := "h"
|
||||
)(trans.following.frag())
|
||||
)(trans.following())
|
||||
case Some(false) => a(
|
||||
cls := "btn-rack__btn relation-button text",
|
||||
title := trans.unblock.txt(),
|
||||
href := s"${routes.Relation.unblock(userId)}?mini=1",
|
||||
dataIcon := "k"
|
||||
)(trans.blocked.frag())
|
||||
)(trans.blocked())
|
||||
case _ => emptyFrag
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,8 +49,8 @@ object form {
|
|||
form3.group(form("throttle"), raw("Throttle in seconds"), help = raw("Optional, to manually throttle requests. Min 2s, max 60s.").some, half = true)(form3.input(_, typ = "number"))
|
||||
),
|
||||
form3.actions(
|
||||
a(href := routes.Relay.index(1))(trans.cancel.frag()),
|
||||
form3.submit(trans.apply.frag())
|
||||
a(href := routes.Relay.index(1))(trans.cancel()),
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -18,28 +18,28 @@ object form {
|
|||
moreJs = captchaTag
|
||||
) {
|
||||
main(cls := "page-small box box-pad report")(
|
||||
h1(trans.reportAUser.frag()),
|
||||
h1(trans.reportAUser()),
|
||||
st.form(
|
||||
cls := "form3",
|
||||
action := s"${routes.Report.create()}${reqUser.??(u => "?username=" + u.username)}",
|
||||
method := "post"
|
||||
)(
|
||||
form3.globalError(form),
|
||||
form3.group(form("username"), trans.user.frag(), klass = "field_to") { f =>
|
||||
form3.group(form("username"), trans.user(), klass = "field_to") { f =>
|
||||
reqUser.map { user =>
|
||||
frag(userLink(user), form3.hidden(f, user.id.some))
|
||||
}.getOrElse {
|
||||
div(form3.input(f, klass = "user-autocomplete")(dataTag := "span"))
|
||||
}
|
||||
},
|
||||
form3.group(form("reason"), trans.reason.frag()) { f =>
|
||||
form3.group(form("reason"), trans.reason()) { f =>
|
||||
form3.select(f, translatedReasonChoices, trans.whatIsIheMatter.txt().some)
|
||||
},
|
||||
form3.group(form("text"), trans.description.frag(), help = trans.reportDescriptionHelp.frag().some)(form3.textarea(_)(rows := 8)),
|
||||
form3.group(form("text"), trans.description(), help = trans.reportDescriptionHelp().some)(form3.textarea(_)(rows := 8)),
|
||||
views.html.base.captcha(form, captcha),
|
||||
form3.actions(
|
||||
a(href := routes.Lobby.home())(trans.cancel.frag()),
|
||||
form3.submit(trans.send.frag())
|
||||
a(href := routes.Lobby.home())(trans.cancel()),
|
||||
form3.submit(trans.send())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -83,10 +83,10 @@ object bits {
|
|||
span(cls := "loss")(s.losses, " L"), " / ",
|
||||
s.ongoing, " ongoing"
|
||||
)
|
||||
} getOrElse trans.currentGames.frag(),
|
||||
} getOrElse trans.currentGames(),
|
||||
"round-toggle-autoswitch" |> { id =>
|
||||
span(cls := "move-on switcher", st.title := trans.automaticallyProceedToNextGameAfterMoving.txt())(
|
||||
label(`for` := id)(trans.autoSwitch.frag()),
|
||||
label(`for` := id)(trans.autoSwitch()),
|
||||
span(cls := "switch")(
|
||||
input(st.id := id, cls := "cmn-toggle", tpe := "checkbox"),
|
||||
label(`for` := id)
|
||||
|
@ -103,7 +103,7 @@ object bits {
|
|||
span(cls := "meta")(
|
||||
playerText(pov.opponent, withRating = false),
|
||||
span(cls := "indicator")(
|
||||
if (pov.isMyTurn) pov.remainingSeconds.fold(trans.yourTurn())(secondsFromNow(_, true))
|
||||
if (pov.isMyTurn) pov.remainingSeconds.fold[Frag](trans.yourTurn())(secondsFromNow(_, true))
|
||||
else nbsp
|
||||
)
|
||||
)
|
||||
|
|
|
@ -38,7 +38,7 @@ private object bits {
|
|||
|
||||
def renderVariant(form: Form[_], variants: List[SelectChoice])(implicit ctx: Context) =
|
||||
div(cls := "variant label_select")(
|
||||
renderLabel(form("variant"), trans.variant.frag()),
|
||||
renderLabel(form("variant"), trans.variant()),
|
||||
renderSelect(form("variant"), variants.filter {
|
||||
case (id, _, _) => ctx.noBlind || lila.game.Game.blindModeVariants.exists(_.id.toString == id)
|
||||
})
|
||||
|
|
|
@ -19,7 +19,7 @@ object forms {
|
|||
def hook(form: Form[_])(implicit ctx: Context) = layout(
|
||||
form,
|
||||
"hook",
|
||||
trans.createAGame.frag(),
|
||||
trans.createAGame(),
|
||||
routes.Setup.hook("uid-placeholder")
|
||||
) {
|
||||
frag(
|
||||
|
@ -31,7 +31,7 @@ object forms {
|
|||
),
|
||||
ctx.noBlind option div(cls := "optional_config")(
|
||||
div(cls := "rating-range-config slider")(
|
||||
trans.ratingRange.frag(),
|
||||
trans.ratingRange(),
|
||||
": ",
|
||||
span(cls := "range")("? - ?"),
|
||||
div(cls := "rating-range")(
|
||||
|
@ -47,26 +47,26 @@ object forms {
|
|||
}
|
||||
|
||||
def ai(form: Form[_], ratings: Map[Int, Int], validFen: Option[lila.setup.ValidFen])(implicit ctx: Context) =
|
||||
layout(form, "ai", trans.playWithTheMachine.frag(), routes.Setup.ai) {
|
||||
layout(form, "ai", trans.playWithTheMachine(), routes.Setup.ai) {
|
||||
frag(
|
||||
renderVariant(form, translatedAiVariantChoices),
|
||||
fenInput(form("fen"), true, validFen),
|
||||
renderTimeMode(form, lila.setup.AiConfig),
|
||||
if (ctx.blind) frag(
|
||||
renderLabel(form("level"), trans.level.frag()),
|
||||
renderLabel(form("level"), trans.level()),
|
||||
renderSelect(form("level"), lila.setup.AiConfig.levelChoices),
|
||||
blindSideChoice(form)
|
||||
)
|
||||
else frag(
|
||||
br,
|
||||
trans.level.frag(),
|
||||
trans.level(),
|
||||
div(cls := "level buttons")(
|
||||
div(id := "config_level")(
|
||||
renderRadios(form("level"), lila.setup.AiConfig.levelChoices)
|
||||
),
|
||||
div(cls := "ai_info")(
|
||||
ratings.toList.map {
|
||||
case (level, rating) => div(cls := s"${prefix}level_$level")(trans.aiNameLevelAiLevel.frag("A.I.", level))
|
||||
case (level, rating) => div(cls := s"${prefix}level_$level")(trans.aiNameLevelAiLevel("A.I.", level))
|
||||
}
|
||||
)
|
||||
)
|
||||
|
@ -101,7 +101,7 @@ object forms {
|
|||
|
||||
private def blindSideChoice(form: Form[_])(implicit ctx: Context) =
|
||||
ctx.blind option frag(
|
||||
renderLabel(form("color"), trans.side.frag()),
|
||||
renderLabel(form("color"), trans.side()),
|
||||
renderSelect(form("color").copy(value = "random".some), translatedSideChoices)
|
||||
)
|
||||
|
||||
|
@ -146,7 +146,7 @@ object forms {
|
|||
div(cls := "ratings")(
|
||||
lila.rating.PerfType.nonPuzzle.map { perfType =>
|
||||
div(cls := perfType.key)(
|
||||
trans.perfRatingX.frag(
|
||||
trans.perfRatingX(
|
||||
raw(s"""<strong data-icon="${perfType.iconChar}">${me.perfs(perfType.key).map(_.intRating).getOrElse("?")}</strong> ${perfType.name}""")
|
||||
)
|
||||
)
|
||||
|
|
|
@ -21,9 +21,9 @@ object bits {
|
|||
title = trans.noSimulFound.txt()
|
||||
) {
|
||||
main(cls := "page-small box box-pad")(
|
||||
h1(trans.noSimulFound.frag()),
|
||||
p(trans.noSimulExplanation.frag()),
|
||||
p(a(href := routes.Simul.home())(trans.returnToSimulHomepage.frag()))
|
||||
h1(trans.noSimulFound()),
|
||||
p(trans.noSimulExplanation()),
|
||||
p(a(href := routes.Simul.home())(trans.returnToSimulHomepage()))
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -20,28 +20,28 @@ object form {
|
|||
moreCss = cssTag("simul.form")
|
||||
) {
|
||||
main(cls := "box box-pad page-small simul-form")(
|
||||
h1(trans.hostANewSimul.frag()),
|
||||
h1(trans.hostANewSimul()),
|
||||
st.form(cls := "form3", action := routes.Simul.create(), method := "POST")(
|
||||
br, br,
|
||||
p(trans.whenCreateSimul.frag()),
|
||||
p(trans.whenCreateSimul()),
|
||||
br, br,
|
||||
globalError(form),
|
||||
form3.group(form("variant"), trans.simulVariantsHint.frag()) { f =>
|
||||
form3.group(form("variant"), trans.simulVariantsHint()) { f =>
|
||||
div(cls := "variants")(
|
||||
views.html.setup.filter.renderCheckboxes(form, "variants", form.value.map(_.variants.map(_.toString)).getOrElse(Nil), translatedVariantChoicesWithVariants)
|
||||
)
|
||||
},
|
||||
form3.split(
|
||||
form3.group(form("clockTime"), raw("Clock initial time"), help = trans.simulClockHint.frag().some, half = true)(form3.select(_, clockTimeChoices)),
|
||||
form3.group(form("clockTime"), raw("Clock initial time"), help = trans.simulClockHint().some, half = true)(form3.select(_, clockTimeChoices)),
|
||||
form3.group(form("clockIncrement"), raw("Clock increment"), half = true)(form3.select(_, clockIncrementChoices))
|
||||
),
|
||||
form3.group(form("clockExtra"), trans.simulHostExtraTime.frag(), help = trans.simulAddExtraTime.frag().some)(
|
||||
form3.group(form("clockExtra"), trans.simulHostExtraTime(), help = trans.simulAddExtraTime().some)(
|
||||
form3.select(_, clockExtraChoices)
|
||||
),
|
||||
form3.group(form("color"), raw("Host color for each game"))(form3.select(_, colorChoices)),
|
||||
form3.actions(
|
||||
a(href := routes.Simul.home())(trans.cancel.frag()),
|
||||
form3.submit(trans.hostANewSimul.frag(), icon = "g".some)
|
||||
a(href := routes.Simul.home())(trans.cancel()),
|
||||
form3.submit(trans.hostANewSimul(), icon = "g".some)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -33,10 +33,10 @@ object home {
|
|||
st.aside(cls := "page-menu__menu simul-list__help")(
|
||||
p(trans.aboutSimul()),
|
||||
img(src := staticUrl("images/fischer-simul.jpg"), alt := "Simul IRL with Bobby Fischer")(
|
||||
em("[1964] ", trans.aboutSimulImage.frag()),
|
||||
p(trans.aboutSimulRealLife.frag()),
|
||||
p(trans.aboutSimulRules.frag()),
|
||||
p(trans.aboutSimulSettings.frag())
|
||||
em("[1964] ", trans.aboutSimulImage()),
|
||||
p(trans.aboutSimulRealLife()),
|
||||
p(trans.aboutSimulRules()),
|
||||
p(trans.aboutSimulSettings())
|
||||
)
|
||||
),
|
||||
div(cls := "page-menu__content simul-list__content")(
|
||||
|
|
|
@ -16,13 +16,13 @@ object homeInner {
|
|||
finisheds: List[lila.simul.Simul]
|
||||
)(implicit ctx: Context) =
|
||||
div(cls := "box")(
|
||||
h1(trans.simultaneousExhibitions.frag()),
|
||||
h1(trans.simultaneousExhibitions()),
|
||||
table(cls := "slist slist-pad")(
|
||||
thead(
|
||||
tr(
|
||||
th(trans.createdSimuls.frag()),
|
||||
th(trans.host.frag()),
|
||||
th(trans.players.frag())
|
||||
th(trans.createdSimuls()),
|
||||
th(trans.host()),
|
||||
th(trans.players())
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
|
@ -35,16 +35,16 @@ object homeInner {
|
|||
},
|
||||
ctx.isAuth option tr(cls := "create")(
|
||||
td(colspan := "4")(
|
||||
a(href := routes.Simul.form(), cls := "action button text")(trans.hostANewSimul.frag())
|
||||
a(href := routes.Simul.form(), cls := "action button text")(trans.hostANewSimul())
|
||||
)
|
||||
)
|
||||
),
|
||||
starteds.nonEmpty option (frag(
|
||||
thead(
|
||||
tr(
|
||||
th(trans.eventInProgress.frag()),
|
||||
th(trans.host.frag()),
|
||||
th(trans.players.frag())
|
||||
th(trans.eventInProgress()),
|
||||
th(trans.host()),
|
||||
th(trans.players())
|
||||
)
|
||||
),
|
||||
starteds.map { sim =>
|
||||
|
@ -57,9 +57,9 @@ object homeInner {
|
|||
)),
|
||||
thead(
|
||||
tr(
|
||||
th(trans.finished.frag()),
|
||||
th(trans.host.frag()),
|
||||
th(trans.players.frag())
|
||||
th(trans.finished()),
|
||||
th(trans.host()),
|
||||
th(trans.players())
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
|
|
|
@ -44,21 +44,21 @@ chat: ${chatOption.fold("null")(c => safeJsonValue(views.html.chat.json(c.chat,
|
|||
div(cls := "setup")(
|
||||
sim.variants.map(_.name).mkString(", "),
|
||||
" • ",
|
||||
trans.casual.frag()
|
||||
trans.casual()
|
||||
)
|
||||
)
|
||||
),
|
||||
trans.simulHostExtraTime.frag(),
|
||||
trans.simulHostExtraTime(),
|
||||
": ",
|
||||
pluralize("minute", sim.clock.hostExtraMinutes),
|
||||
br,
|
||||
trans.hostColorX.frag(sim.color match {
|
||||
case Some("white") => trans.white.frag()
|
||||
case Some("black") => trans.black.frag()
|
||||
case _ => trans.randomColor.frag()
|
||||
trans.hostColorX(sim.color match {
|
||||
case Some("white") => trans.white()
|
||||
case Some("black") => trans.black()
|
||||
case _ => trans.randomColor()
|
||||
})
|
||||
),
|
||||
trans.by.frag(usernameOrId(sim.hostId)),
|
||||
trans.by(usernameOrId(sim.hostId)),
|
||||
" ",
|
||||
momentFromNow(sim.createdAt)
|
||||
),
|
||||
|
|
|
@ -89,7 +89,7 @@ object help {
|
|||
frag(
|
||||
h1("Embed a chess game in your site"),
|
||||
raw(s"""<iframe src="/embed/MPJcy1JW?bg=auto&theme=auto" $args></iframe>"""),
|
||||
p(raw("""On a game analysis page, click the <em>"FEN & PGN"</em> tab at the bottom, then """), "\"", em(trans.embedInYourWebsite.frag(), "\".")),
|
||||
p(raw("""On a game analysis page, click the <em>"FEN & PGN"</em> tab at the bottom, then """), "\"", em(trans.embedInYourWebsite(), "\".")),
|
||||
parameters,
|
||||
p("The text is automatically translated to your visitor's language.")
|
||||
)
|
||||
|
@ -124,18 +124,18 @@ object help {
|
|||
def activeCls(c: String) = cls := active.activeO(c)
|
||||
main(cls := "page-menu")(
|
||||
st.nav(cls := "page-menu__menu subnav")(
|
||||
a(activeCls("about"), href := routes.Page.about)(trans.aboutX.frag("lichess.org")),
|
||||
a(activeCls("about"), href := routes.Page.about)(trans.aboutX("lichess.org")),
|
||||
a(activeCls("faq"), href := routes.Main.faq)("FAQ"),
|
||||
a(activeCls("contact"), href := routes.Main.contact)(trans.contact.frag()),
|
||||
a(activeCls("tos"), href := routes.Page.tos)(trans.termsOfService.frag()),
|
||||
a(activeCls("privacy"), href := routes.Page.privacy)(trans.privacy.frag()),
|
||||
a(activeCls("contact"), href := routes.Main.contact)(trans.contact()),
|
||||
a(activeCls("tos"), href := routes.Page.tos)(trans.termsOfService()),
|
||||
a(activeCls("privacy"), href := routes.Page.privacy)(trans.privacy()),
|
||||
a(activeCls("master"), href := routes.Page.master)("Title verification"),
|
||||
sep,
|
||||
a(activeCls("help"), href := routes.Page.help)(trans.contribute.frag()),
|
||||
a(activeCls("thanks"), href := routes.Page.thanks)(trans.thankYou.frag()),
|
||||
a(activeCls("help"), href := routes.Page.help)(trans.contribute()),
|
||||
a(activeCls("thanks"), href := routes.Page.thanks)(trans.thankYou()),
|
||||
sep,
|
||||
a(activeCls("webmasters"), href := routes.Main.webmasters)(trans.webmasters.frag()),
|
||||
a(activeCls("database"), href := "https://database.lichess.org")(trans.database.frag(), external),
|
||||
a(activeCls("webmasters"), href := routes.Main.webmasters)(trans.webmasters()),
|
||||
a(activeCls("database"), href := "https://database.lichess.org")(trans.database(), external),
|
||||
a(activeCls("api"), href := routes.Api.index)("API", external),
|
||||
a(activeCls("source"), href := "https://github.com/ornicar/lila")("Source code", external),
|
||||
sep,
|
||||
|
|
|
@ -25,7 +25,7 @@ object ratingDistribution {
|
|||
main(cls := "page-menu")(
|
||||
user.bits.communityMenu("ratings"),
|
||||
div(cls := "rating-stats page-menu__content box box-pad")(
|
||||
h1(trans.weeklyPerfTypeRatingDistribution.frag(views.html.base.bits.mselect(
|
||||
h1(trans.weeklyPerfTypeRatingDistribution(views.html.base.bits.mselect(
|
||||
"variant-stats",
|
||||
span(perfType.name),
|
||||
PerfType.leaderboardable map { pt =>
|
||||
|
|
|
@ -124,7 +124,7 @@ object edit {
|
|||
else
|
||||
form3.checkbox(form("approval.ignored"), raw("Ignore further approval requests"), help = modsOnly, half = true)
|
||||
),
|
||||
form3.action(form3.submit(trans.apply.frag()))
|
||||
form3.action(form3.submit(trans.apply()))
|
||||
),
|
||||
form3.split(
|
||||
form3.group(form("twitch"), raw("Your Twitch username or URL"), help = raw("Optional. Leave empty if none").some, half = true)(form3.input(_)),
|
||||
|
@ -138,7 +138,7 @@ object edit {
|
|||
form3.group(form("description"), raw("Long description"))(form3.textarea(_)(rows := 10)),
|
||||
form3.actions(
|
||||
a(href := routes.Streamer.show(s.user.username))("Cancel"),
|
||||
form3.submit(trans.apply.frag())
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -50,7 +50,7 @@ object header {
|
|||
strong(s.status)
|
||||
)
|
||||
} getOrElse frag(
|
||||
p(cls := "at")(trans.lastSeenActive.frag(momentFromNow(s.streamer.seenAt))),
|
||||
p(cls := "at")(trans.lastSeenActive(momentFromNow(s.streamer.seenAt))),
|
||||
s.streamer.liveAt.map { liveAt =>
|
||||
p(cls := "at")("Last stream ", momentFromNow(liveAt))
|
||||
}
|
||||
|
@ -62,8 +62,8 @@ object header {
|
|||
"follow button text" -> true,
|
||||
"active" -> f
|
||||
), tpe := "submit")(
|
||||
span(cls := "active-no")(trans.follow.frag()),
|
||||
span(cls := "active-yes")(trans.following.frag())
|
||||
span(cls := "active-no")(trans.follow()),
|
||||
span(cls := "active-yes")(trans.following())
|
||||
)
|
||||
}
|
||||
)
|
||||
|
|
|
@ -56,7 +56,7 @@ object index {
|
|||
strong(s.status)
|
||||
)
|
||||
} getOrElse frag(
|
||||
p(cls := "at")(trans.lastSeenActive.frag(momentFromNow(s.streamer.seenAt))),
|
||||
p(cls := "at")(trans.lastSeenActive(momentFromNow(s.streamer.seenAt))),
|
||||
s.streamer.liveAt.map { liveAt =>
|
||||
p(cls := "at")("Last stream ", momentFromNow(liveAt))
|
||||
}
|
||||
|
|
|
@ -17,14 +17,14 @@ object bits {
|
|||
),
|
||||
ctx.me.??(_.canTeam) option
|
||||
a(cls := tab.active("mine"), href := routes.Team.mine())(
|
||||
trans.myTeams.frag()
|
||||
trans.myTeams()
|
||||
),
|
||||
a(cls := tab.active("all"), href := routes.Team.all())(
|
||||
trans.allTeams.frag()
|
||||
trans.allTeams()
|
||||
),
|
||||
ctx.me.??(_.canTeam) option
|
||||
a(cls := tab.active("form"), href := routes.Team.form())(
|
||||
trans.newTeam.frag()
|
||||
trans.newTeam()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -22,16 +22,16 @@ object form {
|
|||
h1(trans.newTeam()),
|
||||
st.form(cls := "form3", action := routes.Team.create(), method := "POST")(
|
||||
form3.globalError(form),
|
||||
form3.group(form("name"), trans.name.frag())(form3.input(_)),
|
||||
form3.group(form("open"), trans.joiningPolicy.frag()) { f =>
|
||||
form3.group(form("name"), trans.name())(form3.input(_)),
|
||||
form3.group(form("open"), trans.joiningPolicy()) { f =>
|
||||
form3.select(form("open"), Seq(0 -> trans.aConfirmationIsRequiredToJoin.txt(), 1 -> trans.anyoneCanJoin.txt()))
|
||||
},
|
||||
form3.group(form("location"), trans.location.frag())(form3.input(_)),
|
||||
form3.group(form("description"), trans.description.frag())(form3.textarea(_)(rows := 10)),
|
||||
form3.group(form("location"), trans.location())(form3.input(_)),
|
||||
form3.group(form("description"), trans.description())(form3.textarea(_)(rows := 10)),
|
||||
views.html.base.captcha(form, captcha),
|
||||
form3.actions(
|
||||
a(href := routes.Team.home(1))(trans.cancel()),
|
||||
form3.submit(trans.newTeam.frag())
|
||||
form3.submit(trans.newTeam())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -50,14 +50,14 @@ object form {
|
|||
a(cls := "button button-empty", href := routes.Team.kick(t.id))("Kick someone out of the team"),
|
||||
a(cls := "button button-empty", href := routes.Team.changeOwner(t.id))("Appoint another team owner")
|
||||
),
|
||||
form3.group(form("open"), trans.joiningPolicy.frag()) { f =>
|
||||
form3.group(form("open"), trans.joiningPolicy()) { f =>
|
||||
form3.select(f, Seq(0 -> trans.aConfirmationIsRequiredToJoin.txt(), 1 -> trans.anyoneCanJoin.txt()))
|
||||
},
|
||||
form3.group(form("location"), trans.location.frag())(form3.input(_)),
|
||||
form3.group(form("description"), trans.description.frag())(form3.textarea(_)(rows := 10)),
|
||||
form3.group(form("location"), trans.location())(form3.input(_)),
|
||||
form3.group(form("description"), trans.description())(form3.textarea(_)(rows := 10)),
|
||||
form3.actions(
|
||||
a(href := routes.Team.show(t.id), style := "margin-left:20px")(trans.cancel()),
|
||||
form3.submit(trans.apply.frag())
|
||||
form3.submit(trans.apply())
|
||||
)
|
||||
),
|
||||
hr,
|
||||
|
|
|
@ -31,7 +31,7 @@ object request {
|
|||
views.html.base.captcha(form, captcha),
|
||||
form3.actions(
|
||||
a(href := routes.Team.show(t.slug))(trans.cancel()),
|
||||
form3.submit(trans.joinTeam.frag())
|
||||
form3.submit(trans.joinTeam())
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -26,7 +26,7 @@ object show {
|
|||
h1(cls := "text", dataIcon := "f")(t.name, " ", em("TEAM")),
|
||||
div(
|
||||
if (t.disabled) span(cls := "staff")("CLOSED")
|
||||
else trans.nbMembers.pluralFrag(t.nbMembers, raw("<strong>" + t.nbMembers.localize + "</strong>"))
|
||||
else trans.nbMembers.plural(t.nbMembers, strong(t.nbMembers.localize))
|
||||
)
|
||||
),
|
||||
(info.mine || t.enabled) option div(cls := "team-show__content")(
|
||||
|
|
|
@ -23,7 +23,7 @@ object timeline {
|
|||
moreCss = cssTag("slist")
|
||||
)(
|
||||
main(cls := "timeline page-small box")(
|
||||
h1(trans.timeline.frag()),
|
||||
h1(trans.timeline()),
|
||||
table(cls := "slist slist-pad")(
|
||||
tbody(
|
||||
filterEntries(entries) map { e =>
|
||||
|
@ -40,7 +40,7 @@ object timeline {
|
|||
|
||||
private def entry(e: lila.timeline.Entry)(implicit ctx: Context) = frag(
|
||||
e.decode.map[Frag] {
|
||||
case Follow(u1, u2) => playHtmlToFrag(trans.xStartedFollowingY(userIdLink(u1.some, withOnline = false), userIdLink(u2.some, withOnline = false)))
|
||||
case Follow(u1, u2) => trans.xStartedFollowingY(userIdLink(u1.some, withOnline = false), userIdLink(u2.some, withOnline = false))
|
||||
case TeamJoin(userId, teamId) => trans.xJoinedTeamY(userIdLink(userId.some, withOnline = false), teamLink(teamId, withIcon = false))
|
||||
case TeamCreate(userId, teamId) => trans.xCreatedTeamY(userIdLink(userId.some, withOnline = false), teamLink(teamId, withIcon = false))
|
||||
case ForumPost(userId, topicId, topicName, postId) => trans.xPostedInForumY(userIdLink(userId.some, withOnline = false), raw("""<a href="%s" title="%s">%s</a>""".format(routes.ForumPost.redirect(postId), escapeHtml(topicName), shorten(topicName, 30))))
|
||||
|
|
|
@ -28,12 +28,12 @@ object bits {
|
|||
title = trans.tournamentNotFound.txt()
|
||||
) {
|
||||
main(cls := "page-small box box-pad")(
|
||||
h1(trans.tournamentNotFound.frag()),
|
||||
p(trans.tournamentDoesNotExist.frag()),
|
||||
p(trans.tournamentMayHaveBeenCanceled.frag()),
|
||||
h1(trans.tournamentNotFound()),
|
||||
p(trans.tournamentDoesNotExist()),
|
||||
p(trans.tournamentMayHaveBeenCanceled()),
|
||||
br,
|
||||
br,
|
||||
a(href := routes.Tournament.home())(trans.returnToTournamentsHomepage.frag())
|
||||
a(href := routes.Tournament.home())(trans.returnToTournamentsHomepage())
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -77,12 +77,12 @@ object crud {
|
|||
form3.group(form("clockTime"), raw("Clock time"), half = true)(form3.select(_, DataForm.clockTimeChoices)),
|
||||
form3.group(form("clockIncrement"), raw("Clock increment"), half = true)(form3.select(_, DataForm.clockIncrementChoices))
|
||||
),
|
||||
form3.group(form("position"), trans.startPosition.frag())(tournament.form.startingPosition(_)),
|
||||
form3.group(form("position"), trans.startPosition())(tournament.form.startingPosition(_)),
|
||||
|
||||
hr,
|
||||
h2("Conditions of entry"),
|
||||
tournament.form.condition(form, auto = false, Nil),
|
||||
form3.action(form3.submit(trans.apply.frag()))
|
||||
form3.action(form3.submit(trans.apply()))
|
||||
)
|
||||
|
||||
def index(tours: Paginator[Tournament])(implicit ctx: Context) = layout(
|
||||
|
|
|
@ -25,7 +25,7 @@ object form {
|
|||
h1(trans.createANewTournament()),
|
||||
st.form(cls := "form3", action := routes.Tournament.create, method := "POST")(
|
||||
DataForm.canPickName(me) ?? {
|
||||
form3.group(form("name"), trans.name.frag()) { f =>
|
||||
form3.group(form("name"), trans.name()) { f =>
|
||||
div(
|
||||
form3.input(f), " Arena", br,
|
||||
small(cls := "form-help")(
|
||||
|
@ -37,18 +37,18 @@ object form {
|
|||
}
|
||||
},
|
||||
form3.split(
|
||||
form3.checkbox(form("rated"), trans.rated.frag(), help = raw("Games are rated<br>and impact players ratings").some),
|
||||
form3.checkbox(form("rated"), trans.rated(), help = raw("Games are rated<br>and impact players ratings").some),
|
||||
st.input(tpe := "hidden", name := form("rated").name, value := "false"), // hack allow disabling rated
|
||||
form3.group(form("variant"), trans.variant.frag(), half = true)(form3.select(_, translatedVariantChoicesWithVariants.map(x => x._1 -> x._2)))
|
||||
form3.group(form("variant"), trans.variant(), half = true)(form3.select(_, translatedVariantChoicesWithVariants.map(x => x._1 -> x._2)))
|
||||
),
|
||||
form3.group(form("position"), trans.startPosition.frag(), klass = "position")(startingPosition(_)),
|
||||
form3.group(form("position"), trans.startPosition(), klass = "position")(startingPosition(_)),
|
||||
form3.split(
|
||||
form3.group(form("clockTime"), raw("Clock initial time"), half = true)(form3.select(_, DataForm.clockTimeChoices)),
|
||||
form3.group(form("clockIncrement"), raw("Clock increment"), half = true)(form3.select(_, DataForm.clockIncrementChoices))
|
||||
),
|
||||
form3.split(
|
||||
form3.group(form("minutes"), trans.duration.frag(), half = true)(form3.select(_, DataForm.minuteChoices)),
|
||||
form3.group(form("waitMinutes"), trans.timeBeforeTournamentStarts.frag(), half = true)(form3.select(_, DataForm.waitMinuteChoices))
|
||||
form3.group(form("minutes"), trans.duration(), half = true)(form3.select(_, DataForm.minuteChoices)),
|
||||
form3.group(form("waitMinutes"), trans.timeBeforeTournamentStarts(), half = true)(form3.select(_, DataForm.waitMinuteChoices))
|
||||
),
|
||||
form3.globalError(form),
|
||||
fieldset(cls := "conditions")(
|
||||
|
@ -62,7 +62,7 @@ object form {
|
|||
a(cls := "show")(trans.showAdvancedSettings())
|
||||
),
|
||||
div(cls := "form")(
|
||||
form3.group(form("password"), trans.password.frag(), help = raw("Make the tournament private, and restrict access with a password").some)(form3.input(_)),
|
||||
form3.group(form("password"), trans.password(), help = raw("Make the tournament private, and restrict access with a password").some)(form3.input(_)),
|
||||
condition(form, auto = true, teams = teams),
|
||||
input(tpe := "hidden", name := form("berserkable").name, value := "false"), // hack allow disabling berserk
|
||||
form3.group(form("startDate"), raw("Custom start date"), help = raw("""This overrides the "Time before tournament starts" setting""").some)(form3.flatpickr(_))
|
||||
|
@ -70,7 +70,7 @@ object form {
|
|||
),
|
||||
form3.actions(
|
||||
a(href := routes.Tournament.home())(trans.cancel()),
|
||||
form3.submit(trans.createANewTournament.frag(), icon = "g".some)
|
||||
form3.submit(trans.createANewTournament(), icon = "g".some)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
|
|
@ -38,7 +38,7 @@ var d=lichess.StrongSocket.defaults;d.params.flag="tournament";d.events.reload=a
|
|||
main(cls := "tour-home")(
|
||||
st.aside(cls := "tour-home__side")(
|
||||
h2(
|
||||
a(href := routes.Tournament.leaderboard)(trans.leaderboard.frag())
|
||||
a(href := routes.Tournament.leaderboard)(trans.leaderboard())
|
||||
),
|
||||
ul(cls := "leaderboard")(
|
||||
winners.top.map { w =>
|
||||
|
@ -50,9 +50,9 @@ var d=lichess.StrongSocket.defaults;d.params.flag="tournament";d.events.reload=a
|
|||
),
|
||||
p(cls := "tour__links")(
|
||||
a(href := "/tournament/calendar")(trans.tournamentCalendar()), br,
|
||||
a(href := routes.Tournament.help("arena".some))(trans.tournamentFAQ.frag())
|
||||
a(href := routes.Tournament.help("arena".some))(trans.tournamentFAQ())
|
||||
),
|
||||
h2(trans.lichessTournaments.frag()),
|
||||
h2(trans.lichessTournaments()),
|
||||
div(cls := "scheduled")(
|
||||
scheduled.map { tour =>
|
||||
tour.schedule.filter(s => s.freq != lila.tournament.Schedule.Freq.Hourly) map { s =>
|
||||
|
|
|
@ -34,7 +34,7 @@ object side {
|
|||
separator,
|
||||
tour.durationString
|
||||
),
|
||||
tour.mode.fold(trans.casualTournament, trans.ratedTournament).frag(),
|
||||
tour.mode.fold(trans.casualTournament, trans.ratedTournament)(),
|
||||
separator,
|
||||
systemName(tour.system).capitalize,
|
||||
isGranted(_.TerminateTournament) option
|
||||
|
@ -59,7 +59,7 @@ object side {
|
|||
"accepted" -> (ctx.isAuth && verdicts.accepted),
|
||||
"refused" -> (ctx.isAuth && !verdicts.accepted)
|
||||
))(div(
|
||||
(verdicts.list.size < 2) option p(trans.conditionOfEntry.frag()),
|
||||
(verdicts.list.size < 2) option p(trans.conditionOfEntry()),
|
||||
verdicts.list map { v =>
|
||||
p(cls := List(
|
||||
"condition text" -> true,
|
||||
|
@ -69,7 +69,7 @@ object side {
|
|||
}
|
||||
)),
|
||||
tour.noBerserk option div(cls := "text", dataIcon := "`")("No Berserk allowed"),
|
||||
!tour.isScheduled option frag(trans.by.frag(usernameOrId(tour.createdBy)), br),
|
||||
!tour.isScheduled option frag(trans.by(usernameOrId(tour.createdBy)), br),
|
||||
(!tour.isStarted || (tour.isScheduled && !tour.position.initial)) option absClientDateTime(tour.startsAt),
|
||||
!tour.position.initial option p(
|
||||
a(target := "_blank", href := tour.position.url)(
|
||||
|
|
|
@ -45,7 +45,7 @@ onload=function(){LichessRound.boot({data:${safeJsonValue(data)},i18n:$transJs})
|
|||
div(cls := "round__underboard")(
|
||||
views.html.round.bits.crosstable(cross, pov.game),
|
||||
div(cls := "tv-history")(
|
||||
h2(trans.previouslyOnLichessTV.frag()),
|
||||
h2(trans.previouslyOnLichessTV()),
|
||||
div(cls := "now-playing")(
|
||||
history.map { p =>
|
||||
a(href := gameLink(p))(views.html.game.bits.mini(p))
|
||||
|
|
|
@ -12,9 +12,9 @@ object bits {
|
|||
|
||||
def communityMenu(active: String)(implicit ctx: Context) =
|
||||
st.nav(cls := "page-menu__menu subnav")(
|
||||
a(cls := active.active("leaderboard"), href := routes.User.list)(trans.leaderboard.frag()),
|
||||
a(cls := active.active("ratings"), href := routes.Stat.ratingDistribution("blitz"))(trans.ratingStats.frag()),
|
||||
a(cls := active.active("tournament"), href := routes.Tournament.leaderboard)(trans.tournamentWinners.frag()),
|
||||
a(cls := active.active("leaderboard"), href := routes.User.list)(trans.leaderboard()),
|
||||
a(cls := active.active("ratings"), href := routes.Stat.ratingDistribution("blitz"))(trans.ratingStats()),
|
||||
a(cls := active.active("tournament"), href := routes.Tournament.leaderboard)(trans.tournamentWinners()),
|
||||
a(cls := active.active("shield"), href := routes.Tournament.shields)("Shields")
|
||||
)
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ object list {
|
|||
bits.communityMenu("leaderboard"),
|
||||
div(cls := "community page-menu__content box box-pad")(
|
||||
st.section(cls := "community__online")(
|
||||
h2(trans.onlinePlayers.frag()),
|
||||
h2(trans.onlinePlayers()),
|
||||
ol(cls := "user_top")(online map { u =>
|
||||
li(
|
||||
userLink(u),
|
||||
|
@ -40,7 +40,7 @@ object list {
|
|||
})
|
||||
),
|
||||
div(cls := "community__leaders")(
|
||||
h2(trans.leaderboard.frag()),
|
||||
h2(trans.leaderboard()),
|
||||
div(cls := "leaderboards")(
|
||||
userTopPerf(leaderboards.bullet, PerfType.Bullet),
|
||||
userTopPerf(leaderboards.blitz, PerfType.Blitz),
|
||||
|
@ -68,7 +68,7 @@ object list {
|
|||
private def tournamentWinners(winners: List[lila.tournament.Winner])(implicit ctx: Context) =
|
||||
st.section(cls := "user_top")(
|
||||
h2(cls := "text", dataIcon := "g")(
|
||||
a(href := routes.Tournament.leaderboard)(trans.tournament.frag())
|
||||
a(href := routes.Tournament.leaderboard)(trans.tournament())
|
||||
),
|
||||
ol(winners take 10 map { w =>
|
||||
li(
|
||||
|
|
|
@ -3,8 +3,8 @@ package views.html.user
|
|||
import lila.api.Context
|
||||
import lila.app.templating.Environment._
|
||||
import lila.app.ui.ScalatagsTemplate._
|
||||
import lila.user.User
|
||||
import lila.evaluation.Display
|
||||
import lila.user.User
|
||||
|
||||
import controllers.routes
|
||||
|
||||
|
@ -26,7 +26,7 @@ object mod {
|
|||
)
|
||||
)
|
||||
|
||||
def actions(u: User, emails: User.Emails, erased: User.Erased)(implicit ctx: Context) =
|
||||
def actions(u: User, emails: User.Emails, erased: User.Erased)(implicit ctx: Context): Frag =
|
||||
div(id := "mz_actions")(
|
||||
isGranted(_.UserEvaluate) option div(cls := "btn-rack")(
|
||||
st.form(method := "POST", action := routes.Mod.spontaneousInquiry(u.username), title := "Start an inquiry")(
|
||||
|
@ -223,175 +223,178 @@ object mod {
|
|||
)
|
||||
)
|
||||
|
||||
def assessments(pag: lila.evaluation.PlayerAggregateAssessment.WithGames)(implicit ctx: Context) = div(id := "mz_assessments")(
|
||||
pag.pag.sfAvgBlurs.map { blursYes =>
|
||||
p(cls := "text", dataIcon := "j")(
|
||||
"ACPL in games with blurs is ", strong(blursYes),
|
||||
pag.pag.sfAvgNoBlurs ?? { blursNo =>
|
||||
frag(" against ", strong(blursNo), " in games without blurs.")
|
||||
}
|
||||
)
|
||||
},
|
||||
pag.pag.sfAvgLowVar.map { lowVar =>
|
||||
p(cls := "text", dataIcon := "j")(
|
||||
"ACPL in games with consistent move times is ", strong(lowVar),
|
||||
pag.pag.sfAvgHighVar ?? { highVar =>
|
||||
frag(" against ", strong(highVar), " in games with random move times.")
|
||||
}
|
||||
)
|
||||
},
|
||||
pag.pag.sfAvgHold.map { holdYes =>
|
||||
p(cls := "text", dataIcon := "j")(
|
||||
"ACPL in games with bot signature ", strong(holdYes),
|
||||
pag.pag.sfAvgNoHold.map { holdNo =>
|
||||
frag(" against ", strong(holdNo), " in games without bot signature.")
|
||||
}
|
||||
)
|
||||
},
|
||||
table(cls := "slist")(
|
||||
thead(
|
||||
tr(
|
||||
th("Opponent"),
|
||||
th("Game"),
|
||||
th("Centi-Pawn", br, "(Avg ± SD)"),
|
||||
th("Move Times", br, "(Avg ± SD)"),
|
||||
th(span(title := "The frequency of which the user leaves the game page.")("Blurs")),
|
||||
th(span(title := "Bot detection using grid click analysis.")("Bot")),
|
||||
th(span(title := "Aggregate match")(raw("Σ")))
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
pag.pag.playerAssessments.sortBy(-_.assessment.id).take(15).map { result =>
|
||||
tr(
|
||||
td(
|
||||
a(href := routes.Round.watcher(result.gameId, result.color.name))(
|
||||
pag.pov(result) match {
|
||||
case None => result.gameId
|
||||
case Some(p) => playerLink(p.opponent, withRating = true, withDiff = true, withOnline = false, link = false)
|
||||
}
|
||||
)
|
||||
),
|
||||
td(
|
||||
pag.pov(result).map { p =>
|
||||
a(href := routes.Round.watcher(p.gameId, p.color.name))(
|
||||
p.game.isTournament option iconTag("g"),
|
||||
p.game.perfType.map { pt => iconTag(pt.iconChar) },
|
||||
shortClockName(p.game.clock.map(_.config))
|
||||
)
|
||||
}
|
||||
),
|
||||
td(
|
||||
span(cls := s"sig sig_${Display.stockfishSig(result)}", dataIcon := "J"),
|
||||
s" ${result.sfAvg} ± ${result.sfSd}"
|
||||
),
|
||||
td(
|
||||
span(cls := s"sig sig_${Display.moveTimeSig(result)}", dataIcon := "J"),
|
||||
s" ${result.mtAvg / 10} ± ${result.mtSd / 10}",
|
||||
(~result.mtStreak) ?? frag(br, "STREAK")
|
||||
),
|
||||
td(
|
||||
span(cls := s"sig sig_${Display.blurSig(result)}", dataIcon := "J"),
|
||||
s" ${result.blurs}%",
|
||||
(~result.blurStreak >= 8) ?? frag(br, s"STREAK ${result.blurStreak}/12")
|
||||
),
|
||||
td(
|
||||
span(cls := s"sig sig_${Display.holdSig(result)}", dataIcon := "J"),
|
||||
if (result.hold) "Yes" else "No"
|
||||
),
|
||||
td(
|
||||
div(cls := "aggregate")(
|
||||
span(cls := s"sig sig_${result.assessment.id}")(result.assessment.emoticon)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def otherUsers(u: User, spy: lila.security.UserSpy, notes: List[lila.user.Note], bans: Map[String, Int])(implicit ctx: Context) = div(id := "mz_others")(
|
||||
table(cls := "slist")(
|
||||
thead(
|
||||
tr(
|
||||
th(spy.otherUsers.size, " similar user(s)"),
|
||||
th("Same"),
|
||||
th(attr("data-sort-method") := "number")("Games"),
|
||||
th("Status"),
|
||||
th(attr("data-sort-method") := "number")("Created"),
|
||||
th(attr("data-sort-method") := "number")("Active")
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
spy.withMeSorted(u).map {
|
||||
case lila.security.UserSpy.OtherUser(o, byIp, byFp) => {
|
||||
tr((o == u) option (cls := "same"))(
|
||||
td(attr("data-sort") := o.id)(userLink(o, withBestRating = true, params = "?mod")),
|
||||
td(
|
||||
if (o == u) "-"
|
||||
else List(byIp option "IP", byFp option "Print").flatten.mkString(", ")
|
||||
),
|
||||
td(attr("data-sort") := o.count.game)(o.count.game.localize),
|
||||
td(cls := "i") {
|
||||
val ns = notes.filter(_.to == o.id)
|
||||
frag(
|
||||
ns.nonEmpty option {
|
||||
a(href := s"${routes.User.show(o.username)}?notes")(i(title := s"Notes from ${ns.map(_.from).map(usernameOrId).mkString(", ")}", dataIcon := "m", cls := "is-green"), ns.size)
|
||||
},
|
||||
userMarks(o, bans.get(o.id))
|
||||
)
|
||||
},
|
||||
td(attr("data-sort") := o.createdAt.getMillis)(momentFromNowOnce(o.createdAt)),
|
||||
td(attr("data-sort") := o.seenAt.map(_.getMillis.toString))(o.seenAt.map(momentFromNowOnce))
|
||||
)
|
||||
def assessments(pag: lila.evaluation.PlayerAggregateAssessment.WithGames)(implicit ctx: Context): Frag =
|
||||
div(id := "mz_assessments")(
|
||||
pag.pag.sfAvgBlurs.map { blursYes =>
|
||||
p(cls := "text", dataIcon := "j")(
|
||||
"ACPL in games with blurs is ", strong(blursYes),
|
||||
pag.pag.sfAvgNoBlurs ?? { blursNo =>
|
||||
frag(" against ", strong(blursNo), " in games without blurs.")
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def identification(u: User, spy: lila.security.UserSpy)(implicit ctx: Context) = div(id := "mz_identification")(
|
||||
div(cls := "spy_ips")(
|
||||
strong(spy.ips.size, " IP addresses"),
|
||||
ul(
|
||||
spy.ipsByLocations.map {
|
||||
case (location, ips) => {
|
||||
li(
|
||||
p(location.toString),
|
||||
ul(
|
||||
ips.map { ip =>
|
||||
li(cls := "ip")(
|
||||
a(cls := List("address" -> true, "blocked" -> ip.blocked), href := s"${routes.Mod.search}?q=${ip.ip.value}")(
|
||||
tag("ip")(ip.ip.value.value), " ", momentFromNowOnce(ip.ip.date)
|
||||
)
|
||||
)
|
||||
},
|
||||
pag.pag.sfAvgLowVar.map { lowVar =>
|
||||
p(cls := "text", dataIcon := "j")(
|
||||
"ACPL in games with consistent move times is ", strong(lowVar),
|
||||
pag.pag.sfAvgHighVar ?? { highVar =>
|
||||
frag(" against ", strong(highVar), " in games with random move times.")
|
||||
}
|
||||
)
|
||||
},
|
||||
pag.pag.sfAvgHold.map { holdYes =>
|
||||
p(cls := "text", dataIcon := "j")(
|
||||
"ACPL in games with bot signature ", strong(holdYes),
|
||||
pag.pag.sfAvgNoHold.map { holdNo =>
|
||||
frag(" against ", strong(holdNo), " in games without bot signature.")
|
||||
}
|
||||
)
|
||||
},
|
||||
table(cls := "slist")(
|
||||
thead(
|
||||
tr(
|
||||
th("Opponent"),
|
||||
th("Game"),
|
||||
th("Centi-Pawn", br, "(Avg ± SD)"),
|
||||
th("Move Times", br, "(Avg ± SD)"),
|
||||
th(span(title := "The frequency of which the user leaves the game page.")("Blurs")),
|
||||
th(span(title := "Bot detection using grid click analysis.")("Bot")),
|
||||
th(span(title := "Aggregate match")(raw("Σ")))
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
pag.pag.playerAssessments.sortBy(-_.assessment.id).take(15).map { result =>
|
||||
tr(
|
||||
td(
|
||||
a(href := routes.Round.watcher(result.gameId, result.color.name))(
|
||||
pag.pov(result) match {
|
||||
case None => result.gameId
|
||||
case Some(p) => playerLink(p.opponent, withRating = true, withDiff = true, withOnline = false, link = false)
|
||||
}
|
||||
)
|
||||
),
|
||||
td(
|
||||
pag.pov(result).map { p =>
|
||||
a(href := routes.Round.watcher(p.gameId, p.color.name))(
|
||||
p.game.isTournament option iconTag("g"),
|
||||
p.game.perfType.map { pt => iconTag(pt.iconChar) },
|
||||
shortClockName(p.game.clock.map(_.config))
|
||||
)
|
||||
}
|
||||
),
|
||||
td(
|
||||
span(cls := s"sig sig_${Display.stockfishSig(result)}", dataIcon := "J"),
|
||||
s" ${result.sfAvg} ± ${result.sfSd}"
|
||||
),
|
||||
td(
|
||||
span(cls := s"sig sig_${Display.moveTimeSig(result)}", dataIcon := "J"),
|
||||
s" ${result.mtAvg / 10} ± ${result.mtSd / 10}",
|
||||
(~result.mtStreak) ?? frag(br, "STREAK")
|
||||
),
|
||||
td(
|
||||
span(cls := s"sig sig_${Display.blurSig(result)}", dataIcon := "J"),
|
||||
s" ${result.blurs}%",
|
||||
(~result.blurStreak >= 8) ?? frag(br, s"STREAK ${result.blurStreak}/12")
|
||||
),
|
||||
td(
|
||||
span(cls := s"sig sig_${Display.holdSig(result)}", dataIcon := "J"),
|
||||
if (result.hold) "Yes" else "No"
|
||||
),
|
||||
td(
|
||||
div(cls := "aggregate")(
|
||||
span(cls := s"sig sig_${result.assessment.id}")(result.assessment.emoticon)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
),
|
||||
div(cls := "spy_uas")(
|
||||
strong(spy.uas.size, " User agent(s)"),
|
||||
ul(
|
||||
spy.uas.sorted.map { ua =>
|
||||
li(ua.value, " ", momentFromNowOnce(ua.date))
|
||||
}
|
||||
)
|
||||
),
|
||||
div(cls := "spy_fps")(
|
||||
strong(pluralize("Fingerprint", spy.prints.size)),
|
||||
ul(
|
||||
spy.prints.sorted.map { fp =>
|
||||
li(
|
||||
a(href := s"${routes.Mod.search}?q=${java.net.URLEncoder.encode(fp.value.value, "US-ASCII")}")(
|
||||
fp.value.value, " ", momentFromNowOnce(fp.date)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def otherUsers(u: User, spy: lila.security.UserSpy, notes: List[lila.user.Note], bans: Map[String, Int])(implicit ctx: Context): Frag =
|
||||
div(id := "mz_others")(
|
||||
table(cls := "slist")(
|
||||
thead(
|
||||
tr(
|
||||
th(spy.otherUsers.size, " similar user(s)"),
|
||||
th("Same"),
|
||||
th(attr("data-sort-method") := "number")("Games"),
|
||||
th("Status"),
|
||||
th(attr("data-sort-method") := "number")("Created"),
|
||||
th(attr("data-sort-method") := "number")("Active")
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
spy.withMeSorted(u).map {
|
||||
case lila.security.UserSpy.OtherUser(o, byIp, byFp) => {
|
||||
tr((o == u) option (cls := "same"))(
|
||||
td(attr("data-sort") := o.id)(userLink(o, withBestRating = true, params = "?mod")),
|
||||
td(
|
||||
if (o == u) "-"
|
||||
else List(byIp option "IP", byFp option "Print").flatten.mkString(", ")
|
||||
),
|
||||
td(attr("data-sort") := o.count.game)(o.count.game.localize),
|
||||
td(cls := "i") {
|
||||
val ns = notes.filter(_.to == o.id)
|
||||
frag(
|
||||
ns.nonEmpty option {
|
||||
a(href := s"${routes.User.show(o.username)}?notes")(i(title := s"Notes from ${ns.map(_.from).map(usernameOrId).mkString(", ")}", dataIcon := "m", cls := "is-green"), ns.size)
|
||||
},
|
||||
userMarks(o, bans.get(o.id))
|
||||
)
|
||||
},
|
||||
td(attr("data-sort") := o.createdAt.getMillis)(momentFromNowOnce(o.createdAt)),
|
||||
td(attr("data-sort") := o.seenAt.map(_.getMillis.toString))(o.seenAt.map(momentFromNowOnce))
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def identification(u: User, spy: lila.security.UserSpy)(implicit ctx: Context): Frag =
|
||||
div(id := "mz_identification")(
|
||||
div(cls := "spy_ips")(
|
||||
strong(spy.ips.size, " IP addresses"),
|
||||
ul(
|
||||
spy.ipsByLocations.map {
|
||||
case (location, ips) => {
|
||||
li(
|
||||
p(location.toString),
|
||||
ul(
|
||||
ips.map { ip =>
|
||||
li(cls := "ip")(
|
||||
a(cls := List("address" -> true, "blocked" -> ip.blocked), href := s"${routes.Mod.search}?q=${ip.ip.value}")(
|
||||
tag("ip")(ip.ip.value.value), " ", momentFromNowOnce(ip.ip.date)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
),
|
||||
div(cls := "spy_uas")(
|
||||
strong(spy.uas.size, " User agent(s)"),
|
||||
ul(
|
||||
spy.uas.sorted.map { ua =>
|
||||
li(ua.value, " ", momentFromNowOnce(ua.date))
|
||||
}
|
||||
)
|
||||
),
|
||||
div(cls := "spy_fps")(
|
||||
strong(pluralize("Fingerprint", spy.prints.size)),
|
||||
ul(
|
||||
spy.prints.sorted.map { fp =>
|
||||
li(
|
||||
a(href := s"${routes.Mod.search}?q=${java.net.URLEncoder.encode(fp.value.value, "US-ASCII")}")(
|
||||
fp.value.value, " ", momentFromNowOnce(fp.date)
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
def userMarks(o: User, playbans: Option[Int])(implicit ctx: Context) = div(cls := "user_marks")(
|
||||
playbans.map { nb => iconTag("p", nb.toString)(title := "Playban") },
|
||||
|
|
|
@ -24,7 +24,7 @@ object opponents {
|
|||
td(
|
||||
r.nbGames.filter(_ > 0).map { nbGames =>
|
||||
a(href := s"${routes.User.games(u.username, "search")}?players.b=${r.user.username}", title := "Games count over your last 1000 games")(
|
||||
trans.nbGames.pluralSameFrag(nbGames)
|
||||
trans.nbGames.pluralSame(nbGames)
|
||||
)
|
||||
}
|
||||
),
|
||||
|
|
|
@ -95,7 +95,7 @@ object header {
|
|||
(ctx.noKid && !ctx.is(u)) option div(cls := "note-zone")(
|
||||
form(action := s"${routes.User.writeNote(u.username)}?note", method := "post")(
|
||||
textarea(name := "text", placeholder := "Write a note about this user only you and your friends can read"),
|
||||
button(tpe := "submit", cls := "button")(trans.send.frag()),
|
||||
button(tpe := "submit", cls := "button")(trans.send()),
|
||||
if (isGranted(_.ModNote)) label(style := "margin-left: 1em;")(
|
||||
input(tpe := "checkbox", name := "mod", checked, value := "true", style := "vertical-align: middle;"),
|
||||
"For moderators only"
|
||||
|
@ -137,11 +137,11 @@ object header {
|
|||
!ctx.is(u) option frag(
|
||||
u.engine option div(cls := "warning engine_warning")(
|
||||
span(dataIcon := "j", cls := "is4"),
|
||||
trans.thisPlayerUsesChessComputerAssistance.frag()
|
||||
trans.thisPlayerUsesChessComputerAssistance()
|
||||
),
|
||||
(u.booster && (u.count.game > 0 || isGranted(_.Hunter))) option div(cls := "warning engine_warning")(
|
||||
span(dataIcon := "j", cls := "is4"),
|
||||
trans.thisPlayerArtificiallyIncreasesTheirRating.frag(),
|
||||
trans.thisPlayerArtificiallyIncreasesTheirRating(),
|
||||
(u.count.game == 0) option """
|
||||
Only visible to mods. A booster mark without any games is a way to
|
||||
prevent a player from ever playing (except against boosters/cheaters).
|
||||
|
@ -170,26 +170,26 @@ It's useful against spambots. These marks are not visible to the public."""
|
|||
c.name
|
||||
)
|
||||
},
|
||||
p(cls := "thin")(trans.memberSince.frag(), " ", showDate(u.createdAt)),
|
||||
p(cls := "thin")(trans.memberSince(), " ", showDate(u.createdAt)),
|
||||
u.seenAt.map { seen =>
|
||||
p(cls := "thin")(trans.lastSeenActive.frag(momentFromNow(seen)))
|
||||
p(cls := "thin")(trans.lastSeenActive(momentFromNow(seen)))
|
||||
},
|
||||
info.completionRatePercent.map { c =>
|
||||
p(cls := "thin")(trans.gameCompletionRate.frag(s"$c%"))
|
||||
p(cls := "thin")(trans.gameCompletionRate(s"$c%"))
|
||||
},
|
||||
(ctx is u) option frag(
|
||||
a(href := routes.Account.profile, title := trans.editProfile.txt())(
|
||||
trans.profileCompletion.frag(s"${profile.completionPercent}%")
|
||||
trans.profileCompletion(s"${profile.completionPercent}%")
|
||||
),
|
||||
br,
|
||||
a(href := routes.User.opponents)(trans.favoriteOpponents.frag())
|
||||
a(href := routes.User.opponents)(trans.favoriteOpponents())
|
||||
),
|
||||
info.playTime.map { playTime =>
|
||||
frag(
|
||||
br, br,
|
||||
p(trans.tpTimeSpentPlaying.frag(showPeriod(playTime.totalPeriod))),
|
||||
p(trans.tpTimeSpentPlaying(showPeriod(playTime.totalPeriod))),
|
||||
playTime.nonEmptyTvPeriod.map { tvPeriod =>
|
||||
p(trans.tpTimeSpentOnTV.frag(showPeriod(tvPeriod)))
|
||||
p(trans.tpTimeSpentOnTV(showPeriod(tvPeriod)))
|
||||
}
|
||||
)
|
||||
},
|
||||
|
@ -223,7 +223,7 @@ It's useful against spambots. These marks are not visible to the public."""
|
|||
"active" -> (angle == Angle.Activity)
|
||||
),
|
||||
href := routes.User.show(u.username)
|
||||
)(trans.activity.activity.frag()),
|
||||
)(trans.activity.activity()),
|
||||
a(
|
||||
dataTab := "games",
|
||||
cls := List(
|
||||
|
@ -232,7 +232,7 @@ It's useful against spambots. These marks are not visible to the public."""
|
|||
),
|
||||
href := routes.User.gamesAll(u.username)
|
||||
)(
|
||||
trans.nbGames.pluralFrag(info.user.count.game, info.user.count.game.localize),
|
||||
trans.nbGames.plural(info.user.count.game, info.user.count.game.localize),
|
||||
info.nbs.playing > 0 option
|
||||
span(cls := "unread", title := trans.nbPlaying.pluralTxt(info.nbs.playing, info.nbs.playing.localize))(
|
||||
info.nbs.playing
|
||||
|
|
|
@ -95,7 +95,7 @@ object page {
|
|||
views.html.base.layout(title = u.username, robots = false) {
|
||||
main(cls := "box box-pad")(
|
||||
h1(u.username),
|
||||
p(trans.thisAccountIsClosed.frag())
|
||||
p(trans.thisAccountIsClosed())
|
||||
)
|
||||
}
|
||||
|
||||
|
|
16
build.sbt
16
build.sbt
|
@ -3,7 +3,6 @@ import com.typesafe.sbt.SbtScalariform.autoImport.scalariformFormat
|
|||
import com.typesafe.sbt.web.SbtWeb.autoImport._
|
||||
import play.Play.autoImport._
|
||||
import play.sbt.PlayImport._
|
||||
import play.twirl.sbt.Import._
|
||||
import PlayKeys._
|
||||
|
||||
import BuildSettings._
|
||||
|
@ -36,17 +35,6 @@ libraryDependencies ++= Seq(
|
|||
kamon.core, kamon.influxdb, scalatags,
|
||||
java8compat, semver, scrimage, scalaConfigs, scaffeine
|
||||
)
|
||||
TwirlKeys.templateImports ++= Seq(
|
||||
"lila.game.{ Game, Player, Pov }",
|
||||
"lila.tournament.Tournament",
|
||||
"lila.user.{ User, UserContext }",
|
||||
"lila.security.Permission",
|
||||
"lila.app.templating.Environment._",
|
||||
"lila.api.Context",
|
||||
"lila.i18n.{ I18nKeys => trans }",
|
||||
"lila.common.paginator.Paginator",
|
||||
"lila.common.String.html._"
|
||||
)
|
||||
resourceDirectory in Assets := (sourceDirectory in Compile).value / "assets"
|
||||
unmanagedResourceDirectories in Assets ++= (if (scala.sys.env.get("SERVE_ASSETS").exists(_ == "1")) Seq(baseDirectory.value / "public") else Nil)
|
||||
|
||||
|
@ -140,7 +128,7 @@ lazy val perfStat = module("perfStat", Seq(common, db, user, game, rating)).sett
|
|||
)
|
||||
|
||||
lazy val history = module("history", Seq(common, db, memo, game, user)).settings(
|
||||
libraryDependencies ++= provided(play.api, reactivemongo.driver)
|
||||
libraryDependencies ++= provided(play.api, scalatags, reactivemongo.driver)
|
||||
)
|
||||
|
||||
lazy val db = module("db", Seq(common)).settings(
|
||||
|
@ -238,7 +226,7 @@ lazy val insight = module(
|
|||
Seq(common, game, user, analyse, relation, pref, socket, round, security)
|
||||
).settings(
|
||||
libraryDependencies ++= provided(
|
||||
play.api, reactivemongo.driver, reactivemongo.iteratees
|
||||
play.api, reactivemongo.driver, reactivemongo.iteratees, scalatags
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -2,8 +2,7 @@ package lila.common
|
|||
|
||||
import java.text.Normalizer
|
||||
import play.api.libs.json._
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.RawFrag
|
||||
import scalatags.Text.all._
|
||||
|
||||
import lila.base.RawHtml
|
||||
import lila.common.base.StringUtils.{ safeJsonString, escapeHtml => escapeHtmlRaw }
|
||||
|
@ -50,24 +49,24 @@ final object String {
|
|||
val atUsernameRegex = RawHtml.atUsernameRegex
|
||||
|
||||
object html {
|
||||
def richText(rawText: String, nl2br: Boolean = true) = Html {
|
||||
def richText(rawText: String, nl2br: Boolean = true): Frag = raw {
|
||||
val withLinks = RawHtml.addLinks(rawText)
|
||||
if (nl2br) RawHtml.nl2br(withLinks) else withLinks
|
||||
}
|
||||
|
||||
def nl2brUnsafe(text: String) = Html {
|
||||
RawHtml.nl2br(text)
|
||||
def nl2brUnsafe(text: String): Frag = raw {
|
||||
RawHtml nl2br text
|
||||
}
|
||||
|
||||
def nl2br(text: String): Html = nl2brUnsafe(escapeHtmlRaw(text))
|
||||
def nl2br(text: String): Frag = nl2brUnsafe(escapeHtmlRaw(text))
|
||||
|
||||
def escapeHtml(s: String) = Html {
|
||||
def escapeHtml(s: String): Frag = raw {
|
||||
escapeHtmlRaw(s)
|
||||
}
|
||||
|
||||
def escapeString(s: String) = escapeHtmlRaw(s)
|
||||
def escapeString(s: String): Frag = escapeHtmlRaw(s)
|
||||
|
||||
def markdownLinks(text: String) = Html {
|
||||
def markdownLinks(text: String): Frag = raw {
|
||||
RawHtml.markdownLinks(text)
|
||||
}
|
||||
|
||||
|
@ -88,7 +87,7 @@ final object String {
|
|||
}
|
||||
}
|
||||
|
||||
def safeJsonHtml(jsValue: JsValue) = Html(safeJsonValue(jsValue))
|
||||
def safeJsonHtml(jsValue: JsValue): Frag = raw(safeJsonValue(jsValue))
|
||||
}
|
||||
|
||||
object frag {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package lila.base
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
import play.twirl.api.Html
|
||||
// import scalatags.Text.all._
|
||||
|
||||
import RawHtml._
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package lila.common
|
||||
|
||||
import org.specs2.mutable.Specification
|
||||
import scalatags.Text.all._
|
||||
|
||||
import play.twirl.api.Html
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
class StringTest extends Specification {
|
||||
|
||||
|
@ -16,15 +16,15 @@ class StringTest extends Specification {
|
|||
"richText" should {
|
||||
"handle nl" in {
|
||||
val url = "http://imgur.com/gallery/pMtTE"
|
||||
String.html.richText(s"link to $url here\n") must_== Html {
|
||||
String.html.richText(s"link to $url here\n") must_== raw {
|
||||
s"""link to <a rel="nofollow" href="$url" target="_blank">$url</a> here<br />"""
|
||||
}
|
||||
|
||||
String.html.richText(s"link\n", false) must_== Html("link\n")
|
||||
String.html.richText(s"link\n", false) must_== raw("link\n")
|
||||
}
|
||||
|
||||
"escape chars" in {
|
||||
String.html.richText(s"&") must_== Html("&")
|
||||
String.html.richText(s"&") must_== raw("&")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,26 +1,10 @@
|
|||
package lila.game
|
||||
|
||||
import lila.common.LightUser
|
||||
import lila.user.{ User, Title }
|
||||
import play.twirl.api.Html
|
||||
import lila.user.User
|
||||
|
||||
object Namer {
|
||||
|
||||
def players(game: Game, withRatings: Boolean = true)(implicit lightUser: LightUser.GetterSync): (Html, Html) =
|
||||
player(game.firstPlayer, withRatings) -> player(game.secondPlayer, withRatings)
|
||||
|
||||
def player(p: Player, withRating: Boolean = true, withTitle: Boolean = true)(implicit lightUser: LightUser.GetterSync) = Html {
|
||||
p.aiLevel.fold(
|
||||
p.userId.flatMap(lightUser).fold(lila.user.User.anonymous) { user =>
|
||||
val title = withTitle ?? user.title ?? { t =>
|
||||
s"""<span class="title"${(Title(t) == Title.BOT) ?? " data-bot"} title="${Title titleName Title(t)}">$t</span> """
|
||||
}
|
||||
if (withRating) s"$title${user.name} (${ratingString(p)})"
|
||||
else s"$title${user.name}"
|
||||
}
|
||||
) { level => s"A.I. level $level" }
|
||||
}
|
||||
|
||||
def playerText(player: Player, withRating: Boolean = false)(implicit lightUser: LightUser.GetterSync): String =
|
||||
player.aiLevel.fold(
|
||||
player.userId.flatMap(lightUser).fold(player.name | "Anon.") { u =>
|
||||
|
@ -31,7 +15,7 @@ object Namer {
|
|||
def gameVsText(game: Game, withRatings: Boolean = false)(implicit lightUser: LightUser.GetterSync): String =
|
||||
s"${playerText(game.whitePlayer, withRatings)} - ${playerText(game.blackPlayer, withRatings)}"
|
||||
|
||||
private def ratingString(p: Player) = p.rating match {
|
||||
def ratingString(p: Player) = p.rating match {
|
||||
case Some(rating) => s"$rating${if (p.provisional) "?" else ""}"
|
||||
case _ => "?"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package lila.i18n
|
||||
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.RawFrag
|
||||
|
||||
import lila.common.Lang
|
||||
|
@ -9,26 +8,18 @@ sealed trait I18nKey {
|
|||
|
||||
val key: String
|
||||
|
||||
def literalHtmlTo(lang: Lang, args: Seq[Any] = Seq.empty): Html
|
||||
def pluralHtmlTo(lang: Lang, count: Count, args: Seq[Any] = Nil): Html
|
||||
|
||||
def literalFragTo(lang: Lang, args: Seq[Any] = Seq.empty): RawFrag
|
||||
def pluralFragTo(lang: Lang, count: Count, args: Seq[Any] = Nil): RawFrag
|
||||
def literalTo(lang: Lang, args: Seq[Any] = Seq.empty): RawFrag
|
||||
def pluralTo(lang: Lang, count: Count, args: Seq[Any] = Nil): RawFrag
|
||||
|
||||
def literalTxtTo(lang: Lang, args: Seq[Any] = Seq.empty): String
|
||||
def pluralTxtTo(lang: Lang, count: Count, args: Seq[Any] = Nil): String
|
||||
|
||||
/* Implicit context convenience functions */
|
||||
|
||||
// html
|
||||
def apply(args: Any*)(implicit lang: Lang): Html = literalHtmlTo(lang, args)
|
||||
def plural(count: Count, args: Any*)(implicit lang: Lang): Html = pluralHtmlTo(lang, count, args)
|
||||
def pluralSame(count: Int)(implicit lang: Lang): Html = plural(count, count)
|
||||
|
||||
// frag
|
||||
def frag(args: Any*)(implicit lang: Lang): RawFrag = literalFragTo(lang, args)
|
||||
def pluralFrag(count: Count, args: Any*)(implicit lang: Lang): RawFrag = pluralFragTo(lang, count, args)
|
||||
def pluralSameFrag(count: Int)(implicit lang: Lang): RawFrag = pluralFrag(count, count)
|
||||
def apply(args: Any*)(implicit lang: Lang): RawFrag = literalTo(lang, args)
|
||||
def plural(count: Count, args: Any*)(implicit lang: Lang): RawFrag = pluralTo(lang, count, args)
|
||||
def pluralSame(count: Int)(implicit lang: Lang): RawFrag = plural(count, count)
|
||||
|
||||
// txt
|
||||
def txt(args: Any*)(implicit lang: Lang): String = literalTxtTo(lang, args)
|
||||
|
@ -38,16 +29,10 @@ sealed trait I18nKey {
|
|||
|
||||
final class Translated(val key: String, val db: I18nDb.Ref) extends I18nKey {
|
||||
|
||||
def literalHtmlTo(lang: Lang, args: Seq[Any] = Nil): Html =
|
||||
Translator.html.literal(key, db, args, lang)
|
||||
|
||||
def pluralHtmlTo(lang: Lang, count: Count, args: Seq[Any] = Nil): Html =
|
||||
Translator.html.plural(key, db, count, args, lang)
|
||||
|
||||
def literalFragTo(lang: Lang, args: Seq[Any] = Nil): RawFrag =
|
||||
def literalTo(lang: Lang, args: Seq[Any] = Nil): RawFrag =
|
||||
Translator.frag.literal(key, db, args, lang)
|
||||
|
||||
def pluralFragTo(lang: Lang, count: Count, args: Seq[Any] = Nil): RawFrag =
|
||||
def pluralTo(lang: Lang, count: Count, args: Seq[Any] = Nil): RawFrag =
|
||||
Translator.frag.plural(key, db, count, args, lang)
|
||||
|
||||
def literalTxtTo(lang: Lang, args: Seq[Any] = Nil): String =
|
||||
|
@ -59,11 +44,8 @@ final class Translated(val key: String, val db: I18nDb.Ref) extends I18nKey {
|
|||
|
||||
final class Untranslated(val key: String) extends I18nKey {
|
||||
|
||||
def literalHtmlTo(lang: Lang, args: Seq[Any]) = Html(key)
|
||||
def pluralHtmlTo(lang: Lang, count: Count, args: Seq[Any]) = Html(key)
|
||||
|
||||
def literalFragTo(lang: Lang, args: Seq[Any]) = RawFrag(key)
|
||||
def pluralFragTo(lang: Lang, count: Count, args: Seq[Any]) = RawFrag(key)
|
||||
def literalTo(lang: Lang, args: Seq[Any]) = RawFrag(key)
|
||||
def pluralTo(lang: Lang, count: Count, args: Seq[Any]) = RawFrag(key)
|
||||
|
||||
def literalTxtTo(lang: Lang, args: Seq[Any]) = key
|
||||
def pluralTxtTo(lang: Lang, count: Count, args: Seq[Any]) = key
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
package lila.i18n
|
||||
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.RawFrag
|
||||
import scalatags.Text.all._
|
||||
|
||||
import lila.common.String.html.escapeHtml
|
||||
import lila.common.String.frag.{ escapeHtml => escapeFrag }
|
||||
import lila.common.String.frag.escapeHtml
|
||||
|
||||
private sealed trait Translation
|
||||
|
||||
|
@ -14,14 +12,10 @@ private final class Simple(val message: String) extends Translation {
|
|||
if (args.isEmpty) message
|
||||
else message.format(args: _*)
|
||||
|
||||
def formatFrag(args: Seq[RawFrag]): RawFrag =
|
||||
def format(args: Seq[RawFrag]): RawFrag =
|
||||
if (args.isEmpty) RawFrag(message)
|
||||
else RawFrag(message.format(args.map(_.v): _*))
|
||||
|
||||
def formatHtml(args: Seq[Html]): Html =
|
||||
if (args.isEmpty) Html(message)
|
||||
else Html(message.format(args.map(_.body): _*))
|
||||
|
||||
override def toString = s"Simple($message)"
|
||||
}
|
||||
|
||||
|
@ -31,14 +25,10 @@ private final class Escaped(val message: String, escaped: String) extends Transl
|
|||
if (args.isEmpty) message
|
||||
else message.format(args: _*)
|
||||
|
||||
def formatFrag(args: Seq[RawFrag]): RawFrag =
|
||||
def format(args: Seq[RawFrag]): RawFrag =
|
||||
if (args.isEmpty) RawFrag(escaped)
|
||||
else RawFrag(escaped.format(args.map(_.v): _*))
|
||||
|
||||
def formatHtml(args: Seq[Html]): Html =
|
||||
if (args.isEmpty) Html(escaped)
|
||||
else Html(escaped.format(args.map(_.body): _*))
|
||||
|
||||
override def toString = s"Escaped($message)"
|
||||
}
|
||||
|
||||
|
@ -55,19 +45,12 @@ private final class Plurals(val messages: Map[I18nQuantity, String]) extends Tra
|
|||
else message.format(args: _*)
|
||||
}
|
||||
|
||||
def formatFrag(quantity: I18nQuantity, args: Seq[RawFrag]): Option[RawFrag] =
|
||||
def format(quantity: I18nQuantity, args: Seq[RawFrag]): Option[RawFrag] =
|
||||
messageFor(quantity).map { message =>
|
||||
val escaped = escapeFrag(message)
|
||||
val escaped = escapeHtml(message)
|
||||
if (args.isEmpty) escaped
|
||||
else RawFrag(escaped.v.format(args.map(_.v): _*))
|
||||
}
|
||||
|
||||
def formatHtml(quantity: I18nQuantity, args: Seq[Html]): Option[Html] =
|
||||
messageFor(quantity).map { message =>
|
||||
val escaped = escapeHtml(message)
|
||||
if (args.isEmpty) escaped
|
||||
else Html(escaped.body.format(args.map(_.body): _*))
|
||||
}
|
||||
|
||||
override def toString = s"Plurals($messages)"
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package lila.i18n
|
||||
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.RawFrag
|
||||
import scalatags.Text.all._
|
||||
|
||||
import lila.common.Lang
|
||||
import lila.common.String.html.escapeHtml
|
||||
|
@ -9,41 +8,6 @@ import lila.common.String.frag.{ escapeHtml => escapeFrag }
|
|||
|
||||
object Translator {
|
||||
|
||||
object html {
|
||||
|
||||
def literal(key: MessageKey, db: I18nDb.Ref, args: Seq[Any], lang: Lang): Html =
|
||||
translate(key, db, lang, I18nQuantity.Other /* grmbl */ , args)
|
||||
|
||||
def plural(key: MessageKey, db: I18nDb.Ref, count: Count, args: Seq[Any], lang: Lang): Html =
|
||||
translate(key, db, lang, I18nQuantity(lang, count), args)
|
||||
|
||||
private def translate(key: MessageKey, db: I18nDb.Ref, lang: Lang, quantity: I18nQuantity, args: Seq[Any]): Html =
|
||||
findTranslation(key, db, lang) flatMap { translation =>
|
||||
val htmlArgs = escapeArgs(args)
|
||||
try {
|
||||
translation match {
|
||||
case literal: Simple => Some(literal.formatHtml(htmlArgs))
|
||||
case literal: Escaped => Some(literal.formatHtml(htmlArgs))
|
||||
case plurals: Plurals => plurals.formatHtml(quantity, htmlArgs)
|
||||
}
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
logger.warn(s"Failed to format html $db/$lang/$key -> $translation (${args.toList})", e)
|
||||
Some(Html(key))
|
||||
}
|
||||
} getOrElse {
|
||||
logger.info(s"No translation found for $quantity $key in $lang")
|
||||
Html(key)
|
||||
}
|
||||
|
||||
private def escapeArgs(args: Seq[Any]): Seq[Html] = args.map {
|
||||
case s: String => escapeHtml(s)
|
||||
case h: Html => h
|
||||
case r: RawFrag => Html(r.v)
|
||||
case a => Html(a.toString)
|
||||
}
|
||||
}
|
||||
|
||||
object frag {
|
||||
def literal(key: MessageKey, db: I18nDb.Ref, args: Seq[Any], lang: Lang): RawFrag =
|
||||
translate(key, db, lang, I18nQuantity.Other /* grmbl */ , args)
|
||||
|
@ -56,9 +20,9 @@ object Translator {
|
|||
val htmlArgs = escapeArgs(args)
|
||||
try {
|
||||
translation match {
|
||||
case literal: Simple => Some(literal.formatFrag(htmlArgs))
|
||||
case literal: Escaped => Some(literal.formatFrag(htmlArgs))
|
||||
case plurals: Plurals => plurals.formatFrag(quantity, htmlArgs)
|
||||
case literal: Simple => Some(literal.format(htmlArgs))
|
||||
case literal: Escaped => Some(literal.format(htmlArgs))
|
||||
case plurals: Plurals => plurals.format(quantity, htmlArgs)
|
||||
}
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
|
@ -72,7 +36,6 @@ object Translator {
|
|||
|
||||
private def escapeArgs(args: Seq[Any]): Seq[RawFrag] = args.map {
|
||||
case s: String => escapeFrag(s)
|
||||
case h: Html => RawFrag(h.body)
|
||||
case r: RawFrag => r
|
||||
case a => RawFrag(a.toString)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package lila.insight
|
||||
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.all._
|
||||
import reactivemongo.bson._
|
||||
import play.api.libs.json._
|
||||
|
||||
|
@ -14,7 +14,7 @@ sealed abstract class Dimension[A: BSONValueHandler](
|
|||
val name: String,
|
||||
val dbKey: String,
|
||||
val position: Position,
|
||||
val description: Html
|
||||
val description: Frag
|
||||
) {
|
||||
|
||||
def bson = implicitly[BSONValueHandler[A]]
|
||||
|
@ -32,77 +32,77 @@ object Dimension {
|
|||
|
||||
case object Period extends Dimension[Period](
|
||||
"period", "Date", F.date, Game,
|
||||
Html("The date at which the game was played")
|
||||
raw("The date at which the game was played")
|
||||
)
|
||||
|
||||
case object Date extends Dimension[lila.insight.DateRange](
|
||||
"date", "Date", F.date, Game,
|
||||
Html("The date at which the game was played")
|
||||
raw("The date at which the game was played")
|
||||
)
|
||||
|
||||
case object Perf extends Dimension[PerfType](
|
||||
"variant", "Variant", F.perf, Game,
|
||||
Html("The rating category of the game, like Bullet, Blitz, or Chess960.")
|
||||
raw("The rating category of the game, like Bullet, Blitz, or Chess960.")
|
||||
)
|
||||
|
||||
case object Phase extends Dimension[Phase](
|
||||
"phase", "Game phase", F.moves("p"), Move,
|
||||
Html("The portion of the game: Opening, Middlegame, or Endgame.")
|
||||
raw("The portion of the game: Opening, Middlegame, or Endgame.")
|
||||
)
|
||||
|
||||
case object Result extends Dimension[Result](
|
||||
"result", "Game result", F.result, Game,
|
||||
Html("Whether you won, lost, or drew the game.")
|
||||
raw("Whether you won, lost, or drew the game.")
|
||||
)
|
||||
|
||||
case object Termination extends Dimension[Termination](
|
||||
"termination", "Game termination", F.termination, Game,
|
||||
Html("The way that the game ended, like Checkmate or Resignation.")
|
||||
raw("The way that the game ended, like Checkmate or Resignation.")
|
||||
)
|
||||
|
||||
case object Color extends Dimension[Color](
|
||||
"color", "Color", F.color, Game,
|
||||
Html("The side you are playing: White or Black.")
|
||||
raw("The side you are playing: White or Black.")
|
||||
)
|
||||
|
||||
case object Opening extends Dimension[chess.opening.Ecopening](
|
||||
"opening", "Opening", F.eco, Game,
|
||||
Html("ECO identification of the initial moves, like \"A58 Benko Gambit\".")
|
||||
raw("ECO identification of the initial moves, like \"A58 Benko Gambit\".")
|
||||
)
|
||||
|
||||
case object OpponentStrength extends Dimension[RelativeStrength](
|
||||
"opponentStrength", "Opponent strength", F.opponentStrength, Game,
|
||||
Html("Rating of your opponent compared to yours. Much weaker:-200, Weaker:-100, Stronger:+100, Much stronger:+200.")
|
||||
raw("Rating of your opponent compared to yours. Much weaker:-200, Weaker:-100, Stronger:+100, Much stronger:+200.")
|
||||
)
|
||||
|
||||
case object PieceRole extends Dimension[Role](
|
||||
"piece", "Piece moved", F.moves("r"), Move,
|
||||
Html("The type of piece you move.")
|
||||
raw("The type of piece you move.")
|
||||
)
|
||||
|
||||
case object MovetimeRange extends Dimension[MovetimeRange](
|
||||
"movetime", "Move time", F.moves("t"), Move,
|
||||
Html("The amount of time you spend thinking on each move, in seconds.")
|
||||
raw("The amount of time you spend thinking on each move, in seconds.")
|
||||
)
|
||||
|
||||
case object MyCastling extends Dimension[Castling](
|
||||
"myCastling", "My castling side", F.myCastling, Game,
|
||||
Html("The side you castled on during the game: kingside, queenside, or none.")
|
||||
raw("The side you castled on during the game: kingside, queenside, or none.")
|
||||
)
|
||||
|
||||
case object OpCastling extends Dimension[Castling](
|
||||
"opCastling", "Opponent castling side", F.opponentCastling, Game,
|
||||
Html("The side your opponent castled on during the game: kingside, queenside, or none.")
|
||||
raw("The side your opponent castled on during the game: kingside, queenside, or none.")
|
||||
)
|
||||
|
||||
case object QueenTrade extends Dimension[QueenTrade](
|
||||
"queenTrade", "Queen trade", F.queenTrade, Game,
|
||||
Html("Whether queens were traded before the endgame or not.")
|
||||
raw("Whether queens were traded before the endgame or not.")
|
||||
)
|
||||
|
||||
case object MaterialRange extends Dimension[MaterialRange](
|
||||
"material", "Material imbalance", F.moves("i"), Move,
|
||||
Html("Value of your pieces compared to your opponent's. Pawn=1, Bishop/Knight=3, Rook=5, Queen=9.")
|
||||
raw("Value of your pieces compared to your opponent's. Pawn=1, Bishop/Knight=3, Rook=5, Queen=9.")
|
||||
)
|
||||
|
||||
def requiresStableRating(d: Dimension[_]) = d match {
|
||||
|
|
|
@ -15,7 +15,7 @@ final class JsonView {
|
|||
"key" -> D.Opening.key,
|
||||
"name" -> D.Opening.name,
|
||||
"position" -> D.Opening.position,
|
||||
"description" -> D.Opening.description.body,
|
||||
"description" -> D.Opening.description.render,
|
||||
"values" -> Dimension.valuesOf(D.Opening).filter { o =>
|
||||
ecos contains o.eco
|
||||
}.map(Dimension.valueToJson(D.Opening))
|
||||
|
@ -93,7 +93,7 @@ final class JsonView {
|
|||
"key" -> d.key,
|
||||
"name" -> d.name,
|
||||
"position" -> d.position,
|
||||
"description" -> d.description.body,
|
||||
"description" -> d.description.render,
|
||||
"values" -> Dimension.valuesOf(d).map(Dimension.valueToJson(d))
|
||||
)
|
||||
}
|
||||
|
@ -102,7 +102,7 @@ final class JsonView {
|
|||
Json.obj(
|
||||
"key" -> m.key,
|
||||
"name" -> m.name,
|
||||
"description" -> m.description.body,
|
||||
"description" -> m.description.render,
|
||||
"position" -> m.position
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package lila.insight
|
||||
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.all._
|
||||
|
||||
import reactivemongo.bson._
|
||||
|
||||
sealed abstract class Metric(
|
||||
|
@ -10,7 +11,7 @@ sealed abstract class Metric(
|
|||
val position: Position,
|
||||
val per: Position,
|
||||
val dataType: Metric.DataType,
|
||||
val description: Html
|
||||
val description: Frag
|
||||
)
|
||||
|
||||
object Metric {
|
||||
|
@ -30,7 +31,7 @@ object Metric {
|
|||
import Entry.{ BSONFields => F }
|
||||
|
||||
case object MeanCpl extends Metric("acpl", "Average centipawn loss", F moves "c", Move, Move, Average,
|
||||
Html("""Precision of your moves. Lower is better."""))
|
||||
raw("""Precision of your moves. Lower is better."""))
|
||||
|
||||
case object Movetime extends Metric("movetime", "Move time", F moves "t", Move, Move, Seconds,
|
||||
Dimension.MovetimeRange.description)
|
||||
|
@ -42,22 +43,22 @@ object Metric {
|
|||
Dimension.Termination.description)
|
||||
|
||||
case object RatingDiff extends Metric("ratingDiff", "Rating gain", F.ratingDiff, Game, Game, Average,
|
||||
Html("The amount of rating points you win or lose when the game ends."))
|
||||
raw("The amount of rating points you win or lose when the game ends."))
|
||||
|
||||
case object OpponentRating extends Metric("opponentRating", "Opponent rating", F.opponentRating, Game, Game, Average,
|
||||
Html("The average rating of your opponent for the relevant variant."))
|
||||
raw("The average rating of your opponent for the relevant variant."))
|
||||
|
||||
case object NbMoves extends Metric("nbMoves", "Moves per game", F moves "r", Move, Game, Average,
|
||||
Html("Number of moves you play in the game. Doesn't count the opponent moves."))
|
||||
raw("Number of moves you play in the game. Doesn't count the opponent moves."))
|
||||
|
||||
case object PieceRole extends Metric("piece", "Piece moved", F moves "r", Move, Move, Percent,
|
||||
Dimension.PieceRole.description)
|
||||
|
||||
case object Opportunism extends Metric("opportunism", "Opportunism", F moves "o", Move, Move, Percent,
|
||||
Html("How often you take advantage of your opponent blunders. 100% means you punish them all, 0% means you counter-blunder them all."))
|
||||
raw("How often you take advantage of your opponent blunders. 100% means you punish them all, 0% means you counter-blunder them all."))
|
||||
|
||||
case object Luck extends Metric("luck", "Luck", F moves "l", Move, Move, Percent,
|
||||
Html("How often your opponent fails to punish your blunders. 100% means they miss all your blunders, 0% means they spot them all."))
|
||||
raw("How often your opponent fails to punish your blunders. 100% means they miss all your blunders, 0% means they spot them all."))
|
||||
|
||||
case object Material extends Metric("material", "Material imbalance", F moves "i", Move, Move, Average,
|
||||
Dimension.MaterialRange.description)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package lila.security
|
||||
|
||||
import play.twirl.api.Html
|
||||
import scalatags.Text.all.raw
|
||||
|
||||
import lila.common.{ Lang, EmailAddress }
|
||||
import lila.common.String.html.nl2brUnsafe
|
||||
|
@ -38,7 +38,7 @@ $body
|
|||
|
||||
${Mailgun.txt.serviceNote}
|
||||
""",
|
||||
htmlBody = Html(s"""
|
||||
htmlBody = raw(s"""
|
||||
<div itemscope itemtype="http://schema.org/EmailMessage">
|
||||
<p itemprop="description">${nl2brUnsafe(body)}</p>
|
||||
${Mailgun.html.serviceNote}
|
||||
|
@ -67,7 +67,7 @@ $body
|
|||
|
||||
${Mailgun.txt.serviceNote}
|
||||
""",
|
||||
htmlBody = Html(s"""
|
||||
htmlBody = raw(s"""
|
||||
<div itemscope itemtype="http://schema.org/EmailMessage">
|
||||
<p itemprop="description">${nl2brUnsafe(body)}</p>
|
||||
${Mailgun.html.serviceNote}
|
||||
|
@ -107,7 +107,7 @@ $body
|
|||
|
||||
${Mailgun.txt.serviceNote}
|
||||
""",
|
||||
htmlBody = Html(s"""
|
||||
htmlBody = raw(s"""
|
||||
<div itemscope itemtype="http://schema.org/EmailMessage">
|
||||
<p itemprop="description">${nl2brUnsafe(body)}</p>
|
||||
${Mailgun.html.serviceNote}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue