add game powertips to crosstables and tournament pairings - closes #822

pull/841/head
Thibault Duplessis 2015-08-25 14:23:49 +02:00
parent 1db8d45a5b
commit 35fb4ab9dc
20 changed files with 96 additions and 61 deletions

View File

@ -4,7 +4,7 @@ package actor
import akka.actor._
import play.twirl.api.Html
import lila.game.GameRepo
import lila.game.{ GameRepo, Pov }
import lila.user.UserRepo
import views.{ html => V }
@ -13,7 +13,7 @@ private[app] final class Renderer extends Actor {
def receive = {
case lila.tv.actorApi.RenderFeaturedJs(game) =>
sender ! V.game.featuredJs(game)
sender ! V.game.featuredJs(Pov first game)
case lila.notification.actorApi.RenderNotification(id, from, body) =>
sender ! V.notification.view(id, from)(Html(body))

View File

@ -241,4 +241,10 @@ object Round extends LilaController with TheftPrevention {
Redirect(routes.Lobby.home)
}
}
def mini(gameId: String, color: String) = Open { implicit ctx =>
OptionOk(GameRepo.pov(gameId, color)) { pov =>
html.game.mini(pov)
}
}
}

View File

@ -71,7 +71,7 @@ object Tournament extends LilaController {
def userGameNbMini(id: String, user: String, nb: Int) = Open { implicit ctx =>
withUserGameNb(id, user, nb) { pov =>
Ok(html.game.mini(pov))
Ok(html.tournament.miniGame(pov))
}
}

View File

@ -81,7 +81,7 @@ object Tv extends LilaController {
Env.tv.tv.getBest map {
case None => NotFound
case Some(game) => Ok(views.html.tv.embed(
game,
Pov first game,
get("bg", req) | "light",
lila.pref.Theme(~get("theme", req)).cssClass
))

View File

@ -203,37 +203,37 @@ trait GameHelper { self: I18nHelper with UserHelper with AiHelper with StringHel
}
def gameFen(
game: Game,
color: Color,
pov: Pov,
ownerLink: Boolean = false,
tv: Boolean = false,
withTitle: Boolean = true,
withLink: Boolean = true,
withLive: Boolean = true)(implicit ctx: UserContext) = Html {
val game = pov.game
var isLive = withLive && game.isBeingPlayed
val href = withLink ?? s"""href="${gameLink(game, color, ownerLink, tv)}""""
val title = withTitle ?? s"""title="${gameTitle(game, color)}""""
val href = withLink ?? s"""href="${gameLink(game, pov.color, ownerLink, tv)}""""
val title = withTitle ?? s"""title="${gameTitle(game, pov.color)}""""
val cssClass = isLive ?? ("live live_" + game.id)
val live = isLive ?? game.id
val fen = Forsyth exportBoard game.toChess.board
val lastMove = ~game.castleLastMoveTime.lastMoveString
val variant = game.variant.key
val tag = if (withLink) "a" else "span"
s"""<$tag $href $title class="mini_board mini_board_${game.id} parse_fen is2d $cssClass $variant" data-live="$live" data-color="${color.name}" data-fen="$fen" data-lastmove="$lastMove">$miniBoardContent</$tag>"""
s"""<$tag $href $title class="mini_board mini_board_${game.id} parse_fen is2d $cssClass $variant" data-live="$live" data-color="${pov.color.name}" data-fen="$fen" data-lastmove="$lastMove">$miniBoardContent</$tag>"""
}
def gameFenNoCtx(game: Game, color: Color, tv: Boolean = false, blank: Boolean = false) = Html {
var isLive = game.isBeingPlayed
val variant = game.variant.key
s"""<a href="%s%s" title="%s" class="mini_board mini_board_${game.id} parse_fen is2d %s $variant" data-live="%s" data-color="%s" data-fen="%s" data-lastmove="%s"%s>$miniBoardContent</a>""".format(
def gameFenNoCtx(pov: Pov, tv: Boolean = false, blank: Boolean = false) = Html {
var isLive = pov.game.isBeingPlayed
val variant = pov.game.variant.key
s"""<a href="%s%s" title="%s" class="mini_board mini_board_${pov.game.id} parse_fen is2d %s $variant" data-live="%s" data-color="%s" data-fen="%s" data-lastmove="%s"%s>$miniBoardContent</a>""".format(
blank ?? netBaseUrl,
tv.fold(routes.Tv.index, routes.Round.watcher(game.id, color.name)),
gameTitle(game, color),
isLive ?? ("live live_" + game.id),
isLive ?? game.id,
color.name,
Forsyth exportBoard game.toChess.board,
~game.castleLastMoveTime.lastMoveString,
tv.fold(routes.Tv.index, routes.Round.watcher(pov.game.id, pov.color.name)),
gameTitle(pov.game, pov.color),
isLive ?? ("live live_" + pov.game.id),
isLive ?? pov.game.id,
pov.color.name,
Forsyth exportBoard pov.game.toChess.board,
~pov.game.castleLastMoveTime.lastMoveString,
blank ?? """ target="_blank"""")
}
}

View File

@ -12,7 +12,9 @@
@crosstable.results.zipWithIndex.map {
case (r, index) => {
<td @if(currentId.??(r.gameId==)){class="current"}>
<a href="@routes.Round.watcher(r.gameId, "white")" class="@r.winnerId match {
<a
href="@routes.Round.watcher(r.gameId, "white")"
class="glpt @r.winnerId match {
case Some(w) if w == u.id => { win }
case None => {}
case _ => { loss }
@ -38,4 +40,3 @@
}
</tbody>
</table>

View File

@ -1,3 +1,3 @@
@(g: lila.game.Game)
@gameFenNoCtx(g, g.firstPlayer.color, tv = true)
@game.vstext(g)(none)
@(pov: Pov)
@gameFenNoCtx(pov, tv = true)
@game.vstext(pov)(none)

View File

@ -1,9 +1,3 @@
@(pov: Pov)(implicit ctx: Context)
@gameFen(pov.game, pov.color)
<div class="vstext">
@playerUsername(pov.opponent, withRating = true, withTitle = true)<br />
<span class="result @{(~pov.win).fold("win", (~pov.loss).??("loss"))}">
@gameEndStatus(pov.game)
</span>
</div>
@gameFen(pov)
@vstext(pov)(ctx.some)

View File

@ -1,22 +1,22 @@
@(g: Game)(ctxOption: Option[Context])
@(pov: Pov)(ctxOption: Option[Context])
<div class="vstext clearfix">
<div class="left">
@playerUsername(g.firstPlayer, withRating = false, withTitle = false)
@playerUsername(pov.player, withRating = false, withTitle = false)
<br />
@lightUser(g.firstPlayer.userId).flatMap(_.title).map(_ + " ")
@g.firstPlayer.rating@if(g.firstPlayer.provisional){?}
@lightUser(pov.player.userId).flatMap(_.title).map(_ + " ")
@pov.player.rating@if(pov.player.provisional){?}
</div>
<div class="right">
@playerUsername(g.secondPlayer, withRating = false, withTitle = false)
@playerUsername(pov.opponent, withRating = false, withTitle = false)
<br />
@g.secondPlayer.rating@if(g.secondPlayer.provisional){?}
@lightUser(g.secondPlayer.userId).flatMap(_.title).map(" " + _)
@pov.opponent.rating@if(pov.opponent.provisional){?}
@lightUser(pov.opponent.userId).flatMap(_.title).map(" " + _)
</div>
@g.clock.map { c =>
@pov.game.clock.map { c =>
<div class="center"><span data-icon="p"> @shortClockName(c)</span></div>
}.getOrElse {
@ctxOption.map { ctx =>
@g.daysPerTurn.map { days =>
@pov.game.daysPerTurn.map { days =>
<div class="center">
<span data-hint="@trans.correspondence()(ctx)" class="hint--top">@{(days == 1).fold(trans.oneDay()(ctx), trans.nbDays(days)(ctx))}</span>
</div>

View File

@ -29,7 +29,7 @@
<div class="game_row paginated_element">
@defining(user flatMap g.player) { fromPlayer =>
@defining(fromPlayer | g.firstPlayer ) { firstPlayer =>
@gameFen(g, firstPlayer.color, ownerLink, withTitle = false)
@gameFen(Pov.first(g), ownerLink, withTitle = false)
<a class="game_link_overlay" href="@gameLink(g, firstPlayer.color, ownerLink)"></a>
<div class="infos" data-icon="@gameIcon(g)">
@bookmark.toggle(g)

View File

@ -3,8 +3,8 @@
@underchat = {
<div id="featured_game">
@featured.map { g =>
@gameFen(g, g.firstPlayer.color, tv = true)
@game.vstext(g)(ctx.some)
@gameFen(Pov.first(g), tv = true)
@game.vstext(Pov.first(g))(ctx.some)
}
</div>
}

View File

@ -2,7 +2,7 @@
@povs.take(9).map { pov =>
<a href="@routes.Round.player(pov.fullId)" class="@if(pov.isMyTurn){my_turn}">
@gameFen(pov.game, pov.color, withLink = false, withTitle = false, withLive = false)
@gameFen(pov, withLink = false, withTitle = false, withLive = false)
<span class="meta">
@playerText(pov.opponent, withRating = false)
<span class="indicator">

View File

@ -18,7 +18,7 @@
case (pov, rel) => {
<div>
<a href="@routes.Round.watcher(pov.gameId, pov.color.name)">
@gameFen(pov.game, pov.color, withLink = false, withTitle = false, withLive = false)
@gameFen(pov, withLink = false, withTitle = false, withLive = false)
</a>
<div class="vstext clearfix">
<div class="left">

View File

@ -0,0 +1,9 @@
@(pov: Pov)(implicit ctx: Context)
@gameFen(pov)
<div class="vstext">
@playerUsername(pov.opponent, withRating = true, withTitle = true)<br />
<span class="result @{(~pov.win).fold("win", (~pov.loss).??("loss"))}">
@gameEndStatus(pov.game)
</span>
</div>

View File

@ -1,4 +1,4 @@
@(g: Game, bg: String, theme: String)
@(pov: Pov, bg: String, theme: String)
<!doctype html>
<html>
@ -17,8 +17,8 @@
style="width: 224px; height: 264px; overflow: hidden;"
data-stream-url="@routes.Tv.streamOut">
<div id="featured_game" class="is2d highlight @bg @theme merida" title="lichess.org TV">
@gameFenNoCtx(g, g.firstPlayer.color, tv = true, blank = true)
@game.vstext(g)(none)
@gameFenNoCtx(pov, tv = true, blank = true)
@game.vstext(pov)(none)
</div>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
@jsTag("vendor/chessground.min.js")

View File

@ -6,8 +6,8 @@
@if(filterName == "playing" && gs.nbResults > 2) {
@gs.currentPageResults.flatMap{ Pov(_, u) }.map { p =>
<div class="paginated_element">
@gameFen(p.game, p.color)
@game.vstext(p.game)(ctx.some)
@gameFen(p)
@game.vstext(p)(ctx.some)
</div>
}
} else {

View File

@ -24,7 +24,7 @@
</div>
@if(!ctx.pref.isBlindfold) {
@playing.map { pov =>
@gameFen(pov.game, pov.color)
@gameFen(pov)
<div class="game_legend">
@playerText(pov.opponent, withRating = true)
@pov.game.clock.map { c =>

View File

@ -118,6 +118,8 @@ GET /$gameId<\w{8}>/$color<white|black>/sides/player controllers.Round.sidesPl
GET /$gameId<\w{8}>/others controllers.Round.others(gameId: String)
GET /$gameId<\w{8}>/continue/:mode controllers.Round.continue(gameId: String, mode: String)
POST /$gameId<\w{8}>/note controllers.Round.writeNote(gameId: String)
GET /$gameId<\w{8}>/mini controllers.Round.mini(gameId: String, color: String = "white")
GET /$gameId<\w{8}>/$color<white|black>/mini controllers.Round.mini(gameId: String, color: String)
GET /$gameId<\w{8}>/edit controllers.Editor.game(gameId: String)
GET /$gameId<\w{8}>/$color<white|black>/analysis controllers.UserAnalysis.game(gameId: String, color: String)
POST /$fullId<\w{12}>/resign controllers.Round.resign(fullId: String)

View File

@ -637,7 +637,7 @@ lichess.desktopNotification = function(msg) {
return false;
});
function applyPowertip($els, placement) {
function userPowertip($els, placement) {
$els.removeClass('ulpt').powerTip({
fadeInTime: 100,
fadeOutTime: 100,
@ -657,13 +657,35 @@ lichess.desktopNotification = function(msg) {
}).data('powertip', ' ');
}
function userPowertips() {
applyPowertip($('#site_header .ulpt'), 'e');
applyPowertip($('#friend_box .ulpt'), 'nw');
applyPowertip($('.ulpt'), 'w');
function gamePowertip($els, placement) {
$els.removeClass('glpt').powerTip({
fadeInTime: 100,
fadeOutTime: 100,
placement: placement,
mouseOnToPopup: true,
closeDelay: 200,
popupId: 'miniGame'
}).on({
powerTipPreRender: function() {
$.ajax({
url: ($(this).attr('href') || $(this).data('href')).replace(/\?.+$/, '') + '/mini',
success: function(html) {
$('#miniGame').html(html);
$('body').trigger('lichess.content_loaded');
}
});
}
}).data('powertip', ' ');
}
setTimeout(userPowertips, 600);
$('body').on('lichess.content_loaded', userPowertips);
function updatePowertips() {
userPowertip($('#site_header .ulpt'), 'e');
userPowertip($('#friend_box .ulpt'), 'nw');
userPowertip($('.ulpt'), 'w');
gamePowertip($('.glpt'), 'w');
}
setTimeout(updatePowertips, 600);
$('body').on('lichess.content_loaded', updatePowertips);
$('#message_notifications_tag').on('click', function() {
$.ajax({

View File

@ -22,7 +22,8 @@ module.exports = function(ctrl) {
tag: 'a',
attrs: {
key: p.id,
href: '/' + p.id
href: '/' + p.id,
class: 'glpt'
},
children: [
user(p, 0),