game filter multiple choices wip

This commit is contained in:
Thibault Duplessis 2013-07-26 14:53:04 +02:00
parent a73e5c9cb6
commit c3543ac9d0
11 changed files with 86 additions and 64 deletions

View file

@ -1,12 +1,11 @@
package controllers package controllers
import play.api.data.Form
import play.api.mvc.{ Result, Call }
import lila.app._ import lila.app._
import lila.game.GameRepo import lila.game.GameRepo
import lila.user.UserRepo import lila.user.UserRepo
import lila.user.{ Context, BodyContext } import lila.user.{ Context, BodyContext }
import play.api.data.Form
import play.api.mvc.{ Result, Call }
import views._ import views._
object Setup extends LilaController with TheftPrevention { object Setup extends LilaController with TheftPrevention {
@ -69,7 +68,9 @@ object Setup extends LilaController with TheftPrevention {
} }
def filterForm = Open { implicit ctx def filterForm = Open { implicit ctx
env.forms.filterFilled map { html.setup.filter(_) } env.forms.filterFilled map {
case (form, filter) html.setup.filter(form, filter)
}
} }
def filter = OpenBody { implicit ctx def filter = OpenBody { implicit ctx

View file

@ -29,8 +29,4 @@ trait SetupHelper extends scalaz.Booleans { self: I18nHelper ⇒
} }
} }
} }
def eloDiffChoices(elo: Int)(implicit ctx: Context) = FilterConfig.eloDiffs map { diff
diff -> "%d - %d (±%d)".format(elo - diff, elo + diff, diff)
}
} }

View file

@ -1,24 +1,24 @@
@(form: Form[_])(implicit ctx: Context) @(form: Form[_], filter: lila.setup.FilterConfig)(implicit ctx: Context)
@helper.form(action = routes.Setup.filter(), 'novalidate -> "novalidate") { @helper.form(action = routes.Setup.filter(), 'novalidate -> "novalidate") {
<table> <table>
<tbody> <tbody>
<tr> <tr>
<td>@trans.variant()</td> <td>@trans.variant()</td>
<td>@setup.filterRadios(form, "variant", translatedVariantChoices)</td> <td>@setup.filterCheckboxes(form, "variant", filter.variant.map(_.id.toString), translatedVariantChoices)</td>
</tr> </tr>
<tr> <tr>
<td>@trans.timeControl()</td> <td>@trans.timeControl()</td>
<td>@setup.filterRadios(form, "speed", translatedSpeedChoices)</td> <td>@setup.filterCheckboxes(form, "speed", filter.speed.map(_.id.toString), translatedSpeedChoices)</td>
</tr> </tr>
<tr> <tr>
<td>@trans.mode()</td> <td>@trans.mode()</td>
<td>@setup.filterRadios(form, "mode", translatedModeChoices)</td> <td>@setup.filterCheckboxes(form, "mode", filter.mode.map(_.id.toString), translatedModeChoices)</td>
</tr> </tr>
@ctx.me.map { me => @ctx.me.map { me =>
<tr> <tr>
<td>@trans.eloRange()</td> <td>@trans.eloRange()</td>
<td>@setup.filterRadios(form, "eloDiff", eloDiffChoices(me.elo))</td> <td>@helper.inputText(form("eloRange"))</td>
</tr> </tr>
} }
</tbody> </tbody>

View file

@ -0,0 +1,10 @@
@(form: Form[_], key: String, index: Int, value: String, checks: List[String], text: Html)
<label>
<input
type="checkbox"
name="@{form(key).name}[@index]"
value="@value"
@(if(checks contains value) "checked" else "") />
@text
</label>

View file

@ -0,0 +1,7 @@
@(form: Form[_], key: String, checks: List[String], options: Seq[(Any,String)])(implicit ctx: Context)
@options.zipWithIndex.map {
case ((value, text), index) => {
@setup.filterCheckbox(form, key, index, value.toString, checks, Html(text))
}
}

View file

@ -26,6 +26,11 @@ trait PimpedJson {
def arr(key: String): Option[JsArray] = def arr(key: String): Option[JsArray] =
(js \ key).asOpt[JsArray] (js \ key).asOpt[JsArray]
def ints(key: String): Option[List[Int]] =
(js \ key).asOpt[JsArray] map { arr
arr.value.toList map { v v.asOpt[Int] } flatten
}
def get[A: Reads](key: String): Option[A] = def get[A: Reads](key: String): Option[A] =
(js \ key).asOpt[A] (js \ key).asOpt[A]
} }

View file

@ -4,62 +4,62 @@ import play.api.libs.json._
import chess.{ Variant, Mode, Speed } import chess.{ Variant, Mode, Speed }
import lila.common.PimpedJson._ import lila.common.PimpedJson._
import lila.common.EloRange
case class FilterConfig( case class FilterConfig(
variant: Option[Variant], variant: List[Variant],
mode: Option[Mode], mode: List[Mode],
speed: Option[Speed], speed: List[Speed],
eloDiff: Option[Int]) { eloRange: EloRange) {
def encode = RawFilterConfig( def encode = RawFilterConfig(
v = ~variant.map(_.id), v = variant.map(_.id),
m = mode.map(_.id) | -1, m = mode.map(_.id),
s = ~speed.map(_.id), s = speed.map(_.id),
e = ~eloDiff e = eloRange.toString
) )
def >> = ( def >> = (
variant map (_.id), variant map (_.id),
mode map (_.id), mode map (_.id),
speed map (_.id), speed map (_.id),
eloDiff eloRange.toString
).some ).some
def render = Json.obj( def render = Json.obj(
"variant" -> variant.map(_.toString), "variant" -> variant.map(_.toString),
"mode" -> mode.map(_.toString), "mode" -> mode.map(_.toString),
"speed" -> speed.map(_.id), "speed" -> speed.map(_.id),
"eloDiff" -> eloDiff "eloRange" -> eloRange.toString
) )
} }
object FilterConfig { object FilterConfig {
val variants = List(Variant.Standard, Variant.Chess960)
val modes = Mode.all
val speeds = Speed.all
val default = FilterConfig( val default = FilterConfig(
variant = none, variant = variants,
mode = none, mode = modes,
speed = none, speed = speeds,
eloDiff = none) eloRange = EloRange.default)
val variants = 0 :: Config.variants def <<(v: List[Int], m: List[Int], s: List[Int], e: String) = new FilterConfig(
val modes = -1 :: Mode.all.map(_.id) variant = v map Variant.apply flatten,
val speeds = 0 :: Config.speeds mode = m map Mode.apply flatten,
val eloDiffs = 100 :: 200 :: 300 :: 500 :: Nil speed = s map Speed.apply flatten,
eloRange = EloRange orDefault e
def <<(v: Option[Int], m: Option[Int], s: Option[Int], e: Option[Int]) = new FilterConfig(
variant = v flatMap Variant.apply,
mode = m flatMap Mode.apply,
speed = s flatMap Speed.apply,
eloDiff = e filter (0!=)
) )
def fromDB(obj: JsObject): Option[FilterConfig] = for { def fromDB(obj: JsObject): Option[FilterConfig] = for {
filter obj obj "filter" filter obj obj "filter"
variant filter int "v" variant filter ints "v"
mode filter int "m" mode filter ints "m"
speed filter int "s" speed filter ints "s"
eloDiff filter int "e" eloRange filter str "e"
config RawFilterConfig(variant, mode, speed, eloDiff).decode config RawFilterConfig(variant, mode, speed, eloRange).decode
} yield config } yield config
import lila.db.Tube import lila.db.Tube
@ -79,13 +79,13 @@ object FilterConfig {
) )
} }
private[setup] case class RawFilterConfig(v: Int, m: Int, s: Int, e: Int) { private[setup] case class RawFilterConfig(v: List[Int], m: List[Int], s: List[Int], e: String) {
def decode = FilterConfig( def decode = FilterConfig(
variant = Variant(v), variant = v map Variant.apply flatten,
mode = Mode(m), mode = m map Mode.apply flatten,
speed = Speed(s), speed = s map Speed.apply flatten,
eloDiff = e.some filter (0!=) eloRange = EloRange orDefault e
).some ).some
} }

View file

@ -1,28 +1,27 @@
package lila.setup package lila.setup
import play.api.data._
import play.api.data.Forms._
import chess.Variant import chess.Variant
import lila.common.EloRange import lila.common.EloRange
import lila.db.api._ import lila.db.api._
import lila.lobby.Color import lila.lobby.Color
import lila.user.Context import lila.user.Context
import play.api.data._
import play.api.data.Forms._
import tube.{ userConfigTube, anonConfigTube } import tube.{ userConfigTube, anonConfigTube }
private[setup] final class FormFactory { private[setup] final class FormFactory {
import Mappings._ import Mappings._
def filterFilled(implicit ctx: Context): Fu[Form[FilterConfig]] = def filterFilled(implicit ctx: Context): Fu[(Form[FilterConfig], FilterConfig)] =
filterConfig map filter(ctx).fill filterConfig map { f filter(ctx).fill(f) -> f }
def filter(ctx: Context) = Form( def filter(ctx: Context) = Form(
mapping( mapping(
"variant" -> optional(variant), "variant" -> list(variant),
"mode" -> mode(true), "mode" -> list(rawMode(true)),
"speed" -> optional(speed), "speed" -> list(speed),
"eloDiff" -> optional(eloDiff) "eloRange" -> nonEmptyText
)(FilterConfig.<<)(_.>>) )(FilterConfig.<<)(_.>>)
) )
@ -30,7 +29,7 @@ private[setup] final class FormFactory {
def aiFilled(fen: Option[String])(implicit ctx: Context): Fu[Form[AiConfig]] = def aiFilled(fen: Option[String])(implicit ctx: Context): Fu[Form[AiConfig]] =
aiConfig map { config aiConfig map { config
ai(ctx) fill fen.fold(config) { f ai(ctx) fill fen.fold(config) { f
config.copy(fen = f.some, variant = Variant.FromPosition) config.copy(fen = f.some, variant = Variant.FromPosition)
} }
} }
@ -51,7 +50,7 @@ private[setup] final class FormFactory {
def friendFilled(fen: Option[String])(implicit ctx: Context): Fu[Form[FriendConfig]] = def friendFilled(fen: Option[String])(implicit ctx: Context): Fu[Form[FriendConfig]] =
friendConfig map { config friendConfig map { config
friend(ctx) fill fen.fold(config) { f friend(ctx) fill fen.fold(config) { f
config.copy(fen = f.some, variant = Variant.FromPosition) config.copy(fen = f.some, variant = Variant.FromPosition)
} }
} }
@ -90,6 +89,6 @@ private[setup] final class FormFactory {
def hookConfig(implicit ctx: Context): Fu[HookConfig] = savedConfig map (_.hook) def hookConfig(implicit ctx: Context): Fu[HookConfig] = savedConfig map (_.hook)
def savedConfig(implicit ctx: Context): Fu[UserConfig] = def savedConfig(implicit ctx: Context): Fu[UserConfig] =
ctx.me.fold(AnonConfigRepo config ctx.req)(UserConfigRepo.config) ctx.me.fold(AnonConfigRepo config ctx.req)(UserConfigRepo.config)
} }

View file

@ -13,14 +13,14 @@ object Mappings {
val variantWithFen = number.verifying(Config.variantsWithFen contains _) val variantWithFen = number.verifying(Config.variantsWithFen contains _)
val time = number.verifying(HookConfig.times contains _) val time = number.verifying(HookConfig.times contains _)
val increment = number.verifying(HookConfig.increments contains _) val increment = number.verifying(HookConfig.increments contains _)
def mode(isAuth: Boolean) = optional(number def mode(isAuth: Boolean) = optional(rawMode(isAuth))
def rawMode(isAuth: Boolean) = number
.verifying(HookConfig.modes contains _) .verifying(HookConfig.modes contains _)
.verifying(m m == Mode.Casual.id || isAuth)) .verifying(m m == Mode.Casual.id || isAuth)
val eloRange = optional(nonEmptyText.verifying(EloRange valid _)) val eloRange = optional(nonEmptyText.verifying(EloRange valid _))
val color = nonEmptyText.verifying(Color.names contains _) val color = nonEmptyText.verifying(Color.names contains _)
val level = number.verifying(AiConfig.levels contains _) val level = number.verifying(AiConfig.levels contains _)
val speed = number.verifying(Config.speeds contains _) val speed = number.verifying(Config.speeds contains _)
val eloDiff = number.verifying(FilterConfig.eloDiffs contains _)
def fen(strict: Boolean) = optional { def fen(strict: Boolean) = optional {
nonEmptyText verifying { source ~(Forsyth <<< source).map(_.situation playable strict) } nonEmptyText verifying { source ~(Forsyth <<< source).map(_.situation playable strict) }

View file

@ -2033,7 +2033,7 @@ var storage = {
$div.fadeOut(500); $div.fadeOut(500);
} }
return false; return false;
}); }).click();
$bot.on("click", "tr", function() { $bot.on("click", "tr", function() {
location.href = $(this).find('a.watch').attr("href"); location.href = $(this).find('a.watch').attr("href");

6
todo
View file

@ -57,4 +57,8 @@ customize sound notifications http://imgur.com/70WVyb5
opera issue http://en.lichess.org/forum/lichess-feedback/new-game-wont-show-on-games-list-opera#1 opera issue http://en.lichess.org/forum/lichess-feedback/new-game-wont-show-on-games-list-opera#1
embedded games links http://2ls.ru/chessonline/ embedded games links http://2ls.ru/chessonline/
filter ranges http://en.lichess.org/forum/lichess-feedback/my-proposed-changes-with-filter-window#1 filter ranges http://en.lichess.org/forum/lichess-feedback/my-proposed-changes-with-filter-window#1
takeback en passant http://fr.lichess.org/forum/general-chess-discussion/bug-with-take-back-and-en-passant#2
deploy
------
db.config.update({filter:{$exists:1}},{$unset:{filter:1}},{multi:1})
db.config_anon.update({filter:{$exists:1}},{$unset:{filter:1}},{multi:1})