show realtime user game in powertip
This commit is contained in:
parent
a6235e8a39
commit
7f6314e3ac
|
@ -5,6 +5,7 @@ import play.api.mvc._, Results._
|
||||||
import lila.app._
|
import lila.app._
|
||||||
import lila.common.LilaCookie
|
import lila.common.LilaCookie
|
||||||
import lila.db.api.$find
|
import lila.db.api.$find
|
||||||
|
import lila.game.GameRepo
|
||||||
import lila.security.Permission
|
import lila.security.Permission
|
||||||
import lila.user.tube.userTube
|
import lila.user.tube.userTube
|
||||||
import lila.user.{ Context, User ⇒ UserModel, UserRepo }
|
import lila.user.{ Context, User ⇒ UserModel, UserRepo }
|
||||||
|
@ -21,7 +22,9 @@ object User extends LilaController {
|
||||||
}
|
}
|
||||||
|
|
||||||
def showMini(username: String) = Open { implicit ctx ⇒
|
def showMini(username: String) = Open { implicit ctx ⇒
|
||||||
mini(username)
|
OptionFuOk(UserRepo named username) { user ⇒
|
||||||
|
GameRepo nowPlaying user.id map { html.user.mini(user, _) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def showFilter(username: String, filterName: String, page: Int) = Open { implicit ctx ⇒
|
def showFilter(username: String, filterName: String, page: Int) = Open { implicit ctx ⇒
|
||||||
|
@ -53,12 +56,6 @@ object User extends LilaController {
|
||||||
})
|
})
|
||||||
} yield html.user.show(u, info, pag, filters)
|
} yield html.user.show(u, info, pag, filters)
|
||||||
|
|
||||||
private def mini(username: String)(implicit ctx: Context) =
|
|
||||||
OptionOk(UserRepo named username) { user ⇒
|
|
||||||
Thread sleep 200
|
|
||||||
html.user.mini(user)
|
|
||||||
}
|
|
||||||
|
|
||||||
def list(page: Int) = Open { implicit ctx ⇒
|
def list(page: Int) = Open { implicit ctx ⇒
|
||||||
Reasonable(page) {
|
Reasonable(page) {
|
||||||
val nb = 10
|
val nb = 10
|
||||||
|
|
|
@ -1,25 +1,27 @@
|
||||||
@(userId: String, signup: Boolean = false)(implicit ctx: Context)
|
@(userId: String, signup: Boolean = false, playing: Boolean = false)(implicit ctx: Context)
|
||||||
|
|
||||||
@ctx.userId.map { myId =>
|
@ctx.userId.map { myId =>
|
||||||
@if(myId != userId) {
|
@if(myId != userId) {
|
||||||
@if(!blocks(userId, myId)) {
|
@if(!blocks(userId, myId)) {
|
||||||
|
@if(!playing) {
|
||||||
<a title="@trans.challengeToPlay()" href="@routes.Lobby.home()?username=@userIdToUsername(userId)#friend" class="icon button" href="#">
|
<a title="@trans.challengeToPlay()" href="@routes.Lobby.home()?username=@userIdToUsername(userId)#friend" class="icon button" href="#">
|
||||||
<span class="s16 challenge"></span>
|
<span class="s16 challenge"></span>
|
||||||
</a>
|
</a>
|
||||||
|
}
|
||||||
<a title="@trans.composeMessage()" href="@routes.Message.form()?username=@userId" class="icon button" href="#">
|
<a title="@trans.composeMessage()" href="@routes.Message.form()?username=@userId" class="icon button" href="#">
|
||||||
<span class="s16 message"></span>
|
<span class="s16 message"></span>
|
||||||
</a>
|
</a>
|
||||||
}
|
}
|
||||||
@relationWith(userId) match {
|
@relationWith(userId) match {
|
||||||
case None => {
|
case None => {
|
||||||
<a
|
<a
|
||||||
class="icon button relation"
|
class="icon button relation"
|
||||||
href="@routes.Relation.block(userId)"
|
href="@routes.Relation.block(userId)"
|
||||||
title="@trans.block()">
|
title="@trans.block()">
|
||||||
<span class="s16 tdown"></span>
|
<span class="s16 tdown"></span>
|
||||||
</a>
|
</a>
|
||||||
<a
|
<a
|
||||||
class="icon button relation"
|
class="icon button relation"
|
||||||
href="@routes.Relation.follow(userId)"
|
href="@routes.Relation.follow(userId)"
|
||||||
title="@trans.follow()">
|
title="@trans.follow()">
|
||||||
<span class="s16 tup"></span>
|
<span class="s16 tup"></span>
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
@(u: User)(implicit ctx: Context)
|
@(u: User, playing: Option[Game])(implicit ctx: Context)
|
||||||
<div class="title">
|
<div class="title">
|
||||||
<span class="user_link @isOnline(u.id).fold("online", "offline")">
|
<span class="user_link @isOnline(u.id).fold("online", "offline")">
|
||||||
<strong title="Glicko rating">@u.rating</strong>
|
<strong title="Glicko rating">@u.rating</strong>
|
||||||
<small title="Glicko rating deviation">±@u.perfs.global.glicko.intDeviation</small>
|
<small title="Glicko rating deviation">±@u.perfs.global.glicko.intDeviation</small>
|
||||||
@showProgress(u.progress)
|
@showProgress(u.progress)
|
||||||
@u.count.game.localize @trans.games()
|
@u.count.game.localize @trans.games()
|
||||||
</span>
|
</span>
|
||||||
<p class="localization">
|
<p class="localization">
|
||||||
@u.profileOrDefault.countryInfo.map {
|
@u.profileOrDefault.countryInfo.map {
|
||||||
case (code, name) => {
|
case (code, name) => {
|
||||||
<span class="country"><img src="@staticUrl(s"images/flag/shiny/16/$code.png")" /> @name</span>
|
<span class="country"><img src="@staticUrl(s"images/flag/shiny/16/$code.png")" /> @name</span>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@u.lang.flatMap(langName).map { name =>
|
@u.lang.flatMap(langName).map { name =>
|
||||||
<span class="lang s16">@name</span>
|
<span class="lang s16">@name</span>
|
||||||
}
|
}
|
||||||
</p>
|
</p>
|
||||||
@if(followsMe(u.id)) {
|
@if(followsMe(u.id)) {
|
||||||
@trans.followsYou()
|
@trans.followsYou()
|
||||||
}
|
}
|
||||||
|
@playing.map { g =>
|
||||||
|
@gameFen(g, g.player(u).getOrElse(g.firstPlayer).color)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div class="content relation_actions">@relation.actions(u.id)</div>
|
<div class="content relation_actions">@relation.actions(u.id, playing = playing.isDefined)</div>
|
||||||
|
|
|
@ -164,6 +164,11 @@ trait GameRepo {
|
||||||
$count(Json.obj(BSONFields.createdAt -> ($gte($date(from)) ++ $lt($date(to)))))
|
$count(Json.obj(BSONFields.createdAt -> ($gte($date(from)) ++ $lt($date(to)))))
|
||||||
}).sequenceFu
|
}).sequenceFu
|
||||||
|
|
||||||
|
def nowPlaying(userId: String): Fu[Option[Game]] =
|
||||||
|
$find.one(Query.status(Status.Started) ++ Query.user(userId) ++ Json.obj(
|
||||||
|
BSONFields.createdAt -> $gt($date(DateTime.now - 30.minutes))
|
||||||
|
))
|
||||||
|
|
||||||
def bestOpponents(userId: String, limit: Int): Fu[List[(String, Int)]] = {
|
def bestOpponents(userId: String, limit: Int): Fu[List[(String, Int)]] = {
|
||||||
import reactivemongo.bson._
|
import reactivemongo.bson._
|
||||||
import reactivemongo.core.commands._
|
import reactivemongo.core.commands._
|
||||||
|
|
|
@ -5,7 +5,6 @@ import scala.concurrent.duration._
|
||||||
import akka.actor._
|
import akka.actor._
|
||||||
import akka.pattern.{ ask, pipe }
|
import akka.pattern.{ ask, pipe }
|
||||||
import chess.Color
|
import chess.Color
|
||||||
import makeTimeout.short
|
|
||||||
import play.api.libs.json.{ JsObject, Json }
|
import play.api.libs.json.{ JsObject, Json }
|
||||||
|
|
||||||
import actorApi._, round._
|
import actorApi._, round._
|
||||||
|
@ -16,6 +15,7 @@ import lila.security.Flood
|
||||||
import lila.socket.actorApi.{ Connected ⇒ _, _ }
|
import lila.socket.actorApi.{ Connected ⇒ _, _ }
|
||||||
import lila.socket.Handler
|
import lila.socket.Handler
|
||||||
import lila.user.{ User, Context }
|
import lila.user.{ User, Context }
|
||||||
|
import makeTimeout.short
|
||||||
|
|
||||||
private[round] final class SocketHandler(
|
private[round] final class SocketHandler(
|
||||||
roundMap: ActorRef,
|
roundMap: ActorRef,
|
||||||
|
@ -78,6 +78,9 @@ private[round] final class SocketHandler(
|
||||||
case ("challenge", o) ⇒ ((o str "d") |@| member.userId).tupled foreach {
|
case ("challenge", o) ⇒ ((o str "d") |@| member.userId).tupled foreach {
|
||||||
case (to, from) ⇒ hub.actor.challenger ! lila.hub.actorApi.setup.RemindChallenge(gameId, from, to)
|
case (to, from) ⇒ hub.actor.challenger ! lila.hub.actorApi.setup.RemindChallenge(gameId, from, to)
|
||||||
}
|
}
|
||||||
|
case ("liveGames", o) ⇒ o str "d" foreach { ids ⇒
|
||||||
|
socket ! LiveGames(uid, ids.split(' ').toList)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,8 @@ final class SocketHub extends Actor {
|
||||||
|
|
||||||
private val sockets = collection.mutable.Set[ActorRef]()
|
private val sockets = collection.mutable.Set[ActorRef]()
|
||||||
|
|
||||||
context.system.lilaBus.subscribe(self,
|
context.system.lilaBus.subscribe(self,
|
||||||
'moveEvent, 'users, 'deploy, 'nbMembers, 'socket,
|
'moveEvent, 'users, 'deploy, 'nbMembers, 'socket,
|
||||||
// FIXME this event only concern the current TV room
|
// FIXME this event only concern the current TV room
|
||||||
'changeFeaturedGame)
|
'changeFeaturedGame)
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,13 @@ var storage = {
|
||||||
//////////////////
|
//////////////////
|
||||||
|
|
||||||
var strongSocketDefaults = {
|
var strongSocketDefaults = {
|
||||||
events: {},
|
events: {
|
||||||
|
fen: function(e) {
|
||||||
|
$('a.live_' + e.id).each(function() {
|
||||||
|
parseFen($(this).data("fen", e.fen).data("lastmove", e.lm));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
params: {
|
params: {
|
||||||
sri: lichess_sri
|
sri: lichess_sri
|
||||||
},
|
},
|
||||||
|
@ -498,6 +504,7 @@ var storage = {
|
||||||
url: $(this).attr('href') + '/mini',
|
url: $(this).attr('href') + '/mini',
|
||||||
success: function(html) {
|
success: function(html) {
|
||||||
$('#powerTip').html(html);
|
$('#powerTip').html(html);
|
||||||
|
$('body').trigger('lichess.content_loaded');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1739,93 +1746,93 @@ var storage = {
|
||||||
// gamelist.js //
|
// gamelist.js //
|
||||||
/////////////////
|
/////////////////
|
||||||
|
|
||||||
$(function() {
|
function parseFen($elem) {
|
||||||
|
if (!$elem || !$elem.jquery) {
|
||||||
function parseFen($elem) {
|
$elem = $('.parse_fen');
|
||||||
if (!$elem || !$elem.jquery) {
|
|
||||||
$elem = $('.parse_fen');
|
|
||||||
}
|
|
||||||
$elem.each(function() {
|
|
||||||
var $this = $(this);
|
|
||||||
var color = $this.data('color') || "white";
|
|
||||||
var withKeys = $this.hasClass('with_keys');
|
|
||||||
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
|
|
||||||
var fen = $this.data('fen').split(' ')[0].replace(/\//g, '');
|
|
||||||
var lm = $this.data('lastmove');
|
|
||||||
var lastMove = lm ? [lm[0] + lm[1], lm[2] + lm[3]] : [];
|
|
||||||
var x, y, html = '',
|
|
||||||
scolor, pcolor, pclass, c, d, increment;
|
|
||||||
var pclasses = {
|
|
||||||
'p': 'pawn',
|
|
||||||
'r': 'rook',
|
|
||||||
'n': 'knight',
|
|
||||||
'b': 'bishop',
|
|
||||||
'q': 'queen',
|
|
||||||
'k': 'king'
|
|
||||||
};
|
|
||||||
var pregex = /(p|r|n|b|q|k)/;
|
|
||||||
|
|
||||||
if ('white' == color) {
|
|
||||||
x = 8;
|
|
||||||
y = 1;
|
|
||||||
increment = function() {
|
|
||||||
y++;
|
|
||||||
if (y > 8) {
|
|
||||||
y = 1;
|
|
||||||
x--;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
x = 1;
|
|
||||||
y = 8;
|
|
||||||
increment = function() {
|
|
||||||
y--;
|
|
||||||
if (y < 1) {
|
|
||||||
y = 8;
|
|
||||||
x++;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function openSquare(x, y) {
|
|
||||||
var key = 'white' == color ? letters[y - 1] + x : letters[8 - y] + (9 - x);
|
|
||||||
var scolor = (x + y) % 2 ? 'white' : 'black';
|
|
||||||
if ($.inArray(key, lastMove) != -1) scolor += " moved";
|
|
||||||
var html = '<div class="lmcs ' + scolor + '" style="top:' + (28 * (8 - x)) + 'px;left:' + (28 * (y - 1)) + 'px;"';
|
|
||||||
if (withKeys) {
|
|
||||||
html += ' data-key="' + key + '"';
|
|
||||||
}
|
|
||||||
return html + '>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeSquare() {
|
|
||||||
return '</div>';
|
|
||||||
}
|
|
||||||
|
|
||||||
for (var fenIndex in fen) {
|
|
||||||
c = fen[fenIndex];
|
|
||||||
html += openSquare(x, y);
|
|
||||||
if (!isNaN(c)) { // it is numeric
|
|
||||||
html += closeSquare();
|
|
||||||
increment();
|
|
||||||
for (d = 1; d < c; d++) {
|
|
||||||
html += openSquare(x, y) + closeSquare();
|
|
||||||
increment();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pcolor = pregex.test(c) ? 'black' : 'white';
|
|
||||||
pclass = pclasses[c.toLowerCase()];
|
|
||||||
html += '<div class="lcmp ' + pclass + ' ' + pcolor + '"></div>';
|
|
||||||
html += closeSquare();
|
|
||||||
increment();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$this.html(html).removeClass('parse_fen');
|
|
||||||
// attempt to free memory
|
|
||||||
html = pclasses = increment = pregex = fen = $this = 0;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
$elem.each(function() {
|
||||||
|
var $this = $(this);
|
||||||
|
var color = $this.data('color') || "white";
|
||||||
|
var withKeys = $this.hasClass('with_keys');
|
||||||
|
var letters = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'];
|
||||||
|
var fen = $this.data('fen').split(' ')[0].replace(/\//g, '');
|
||||||
|
var lm = $this.data('lastmove');
|
||||||
|
var lastMove = lm ? [lm[0] + lm[1], lm[2] + lm[3]] : [];
|
||||||
|
var x, y, html = '',
|
||||||
|
scolor, pcolor, pclass, c, d, increment;
|
||||||
|
var pclasses = {
|
||||||
|
'p': 'pawn',
|
||||||
|
'r': 'rook',
|
||||||
|
'n': 'knight',
|
||||||
|
'b': 'bishop',
|
||||||
|
'q': 'queen',
|
||||||
|
'k': 'king'
|
||||||
|
};
|
||||||
|
var pregex = /(p|r|n|b|q|k)/;
|
||||||
|
|
||||||
|
if ('white' == color) {
|
||||||
|
x = 8;
|
||||||
|
y = 1;
|
||||||
|
increment = function() {
|
||||||
|
y++;
|
||||||
|
if (y > 8) {
|
||||||
|
y = 1;
|
||||||
|
x--;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
x = 1;
|
||||||
|
y = 8;
|
||||||
|
increment = function() {
|
||||||
|
y--;
|
||||||
|
if (y < 1) {
|
||||||
|
y = 8;
|
||||||
|
x++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function openSquare(x, y) {
|
||||||
|
var key = 'white' == color ? letters[y - 1] + x : letters[8 - y] + (9 - x);
|
||||||
|
var scolor = (x + y) % 2 ? 'white' : 'black';
|
||||||
|
if ($.inArray(key, lastMove) != -1) scolor += " moved";
|
||||||
|
var html = '<div class="lmcs ' + scolor + '" style="top:' + (28 * (8 - x)) + 'px;left:' + (28 * (y - 1)) + 'px;"';
|
||||||
|
if (withKeys) {
|
||||||
|
html += ' data-key="' + key + '"';
|
||||||
|
}
|
||||||
|
return html + '>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSquare() {
|
||||||
|
return '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var fenIndex in fen) {
|
||||||
|
c = fen[fenIndex];
|
||||||
|
html += openSquare(x, y);
|
||||||
|
if (!isNaN(c)) { // it is numeric
|
||||||
|
html += closeSquare();
|
||||||
|
increment();
|
||||||
|
for (d = 1; d < c; d++) {
|
||||||
|
html += openSquare(x, y) + closeSquare();
|
||||||
|
increment();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pcolor = pregex.test(c) ? 'black' : 'white';
|
||||||
|
pclass = pclasses[c.toLowerCase()];
|
||||||
|
html += '<div class="lcmp ' + pclass + ' ' + pcolor + '"></div>';
|
||||||
|
html += closeSquare();
|
||||||
|
increment();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this.html(html).removeClass('parse_fen');
|
||||||
|
// attempt to free memory
|
||||||
|
html = pclasses = increment = pregex = fen = $this = 0;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
$(function() {
|
||||||
parseFen();
|
parseFen();
|
||||||
$('body').on('lichess.content_loaded', parseFen);
|
$('body').on('lichess.content_loaded', parseFen);
|
||||||
|
|
||||||
|
@ -1847,13 +1854,6 @@ var storage = {
|
||||||
registerLiveGames();
|
registerLiveGames();
|
||||||
});
|
});
|
||||||
|
|
||||||
lichess.socketDefaults.events.fen = function(e) {
|
|
||||||
$('a.live_' + e.id).each(function() {
|
|
||||||
var $this = $(this);
|
|
||||||
parseFen($this.data("fen", e.fen).data("lastmove", e.lm));
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$('div.checkmateCaptcha').each(function() {
|
$('div.checkmateCaptcha').each(function() {
|
||||||
var $captcha = $(this);
|
var $captcha = $(this);
|
||||||
var color = $captcha.find('.mini_board').data('color');
|
var color = $captcha.find('.mini_board').data('color');
|
||||||
|
|
Loading…
Reference in a new issue