update embedded TV frame mini-game

pull/7129/head
Thibault Duplessis 2020-08-17 20:19:46 +02:00
parent 4d534dd954
commit 10e44190c5
12 changed files with 161 additions and 190 deletions

View File

@ -1,18 +1,19 @@
package views.html.game
import chess.format.Forsyth
import controllers.routes
import lila.api.Context
import lila.app.templating.Environment._
import lila.app.ui.ScalatagsTemplate._
import lila.game.Pov
import controllers.routes
import chess.format.Forsyth
object mini {
private val dataLive = attr("data-live")
private val dataState = attr("data-state")
private val dataTime = attr("data-time")
private val cgWrap = span(cls := "cg-wrap")(cgWrapContent)
def apply(
pov: Pov,
@ -30,7 +31,7 @@ object mini {
renderState(pov)
)(
renderPlayer(!pov),
span(cls := "cg-wrap")(cgWrapContent),
cgWrap,
renderPlayer(pov)
)
}
@ -40,13 +41,12 @@ object mini {
val isLive = game.isBeingPlayed
a(
href := (if (tv) routes.Tv.index() else routes.Round.watcher(pov.gameId, pov.color.name)),
title := gameTitle(pov.game, pov.color),
cls := s"mini-game mini-game-${game.id} mini-game--init is2d ${isLive ?? "mini-game--live"} ${game.variant.key}",
dataLive := isLive.option(game.id),
renderState(pov)
)(
renderPlayer(!pov),
span(cls := "cg-wrap")(cgWrapContent),
cgWrap,
renderPlayer(pov)
)
}

View File

@ -31,6 +31,7 @@ object embed {
),
jQueryTag,
jsAt("javascripts/vendor/chessground.min.js", defer = false),
jsAt("compiled/util.js", defer = false),
jsAt("compiled/tv.js", defer = false)
)
)

View File

@ -47,13 +47,16 @@ final private class TvBroadcast extends Actor {
featuredId = id.some
queues.foreach(_ offer msg)
case MoveGameEvent(_, fen, move) if queues.nonEmpty =>
case MoveGameEvent(game, fen, move) if queues.nonEmpty =>
val msg = makeMessage(
"fen",
Json.obj(
"fen" -> fen,
"lm" -> move
)
Json
.obj(
"fen" -> s"$fen ${game.turnColor.letter}",
"lm" -> move
)
.add("cw" -> game.clock.map(_.remainingTime(chess.White).roundSeconds))
.add("bw" -> game.clock.map(_.remainingTime(chess.Black).roundSeconds))
)
queues.foreach(_ offer msg)
}

View File

@ -81,7 +81,8 @@ object Tv {
name = "Top Rated",
icon = "C",
secondsSinceLastMove = freshBlitz,
filters = Seq(rated(2150), standard, noBot)
filters = Seq(rated(150), standard, noBot)
// filters = Seq(rated(2150), standard, noBot)
)
case object Bullet
extends Channel(

View File

@ -10,6 +10,6 @@
}
}
.mini-board, .mini-game .cg-wrap {
.cg-wrap {
@extend %square;
}

View File

@ -12,6 +12,7 @@
padding: 0 2px;
}
&__user {
overflow: hidden;
}

View File

@ -10,12 +10,6 @@
z-index: z("powertip");
}
#powerTip {
.mini-board {
border-width: 0 0 1px 0;
}
}
.upt {
&__info {
@extend %flex-column;

View File

@ -1,4 +1,4 @@
@import "../../../common/css/embed";
@import "../../../common/css/component/board";
@import "../../../common/css/component/vs";
@import "../../../common/css/component/mini-game";
@import "../tv/embed";

View File

@ -4,19 +4,14 @@ body {
}
.embedded {
.vstext, cg-board {
background: $c-bg-page;
padding: .3em;
cg-board {
box-shadow: none;
}
cg-board {
border-radius: 3px 3px 0 0;
}
.vstext {
@extend %metal;
border-radius: 0 0 3px 3px;
border: $border;
border-top: 0;
}
}

View File

@ -191,96 +191,6 @@
});
};
lichess.miniBoard = {
initAll() {
Array.from(document.getElementsByClassName('mini-board--init')).forEach(lichess.miniBoard.init);
},
init(node) {
if (!window.Chessground) return setTimeout(() => lichess.miniBoard.init(node), 500);
const $el = $(node).removeClass('mini-board--init'),
[fen, orientation, lm] = $el.data('state').split(',');
$el.data('chessground', Chessground(node, {
orientation,
coordinates: false,
viewOnly: !node.getAttribute('data-playable'),
resizable: false,
fen,
lastMove: lm && (lm[1] === '@' ? [lm.slice(2)] : [lm[0] + lm[1], lm[2] + lm[3]]),
drawable: {
enabled: false,
visible: false
}
}));
}
};
lichess.miniGame = (() => {
const fenColor = fen => fen.indexOf(' b') > 0 ? 'black' : 'white';
return {
init(node, data) {
const [fen, orientation, lm] = ((typeof data == 'string' && data) || node.getAttribute('data-state')).split(','),
config = {
coordinates: false,
viewOnly: true,
resizable: false,
fen,
orientation,
lastMove: lm && (lm[1] === '@' ? [lm.slice(2)] : [lm[0] + lm[1], lm[2] + lm[3]]),
drawable: {
enabled: false,
visible: false
}
},
$el = $(node).removeClass('mini-game--init'),
$cg = $el.find('.cg-wrap'),
turnColor = fenColor(fen);
$cg.data('chessground', Chessground($cg[0], config));
['white', 'black'].forEach(color =>
$el.find('.mini-game__clock--' + color).each(function() {
$(this).clock({
time: parseInt(this.getAttribute('data-time')),
pause: color != turnColor
});
})
);
return node.getAttribute('data-live');
},
initAll() {
const nodes = Array.from(document.getElementsByClassName('mini-game--init')),
ids = nodes.map(lichess.miniGame.init).filter(id => id);
if (ids.length) window.lichess.StrongSocket.firstConnect.then(send =>
send('startWatching', ids.join(' '))
);
},
update(node, data) {
const $el = $(node),
lm = data.lm,
lastMove = lm && (lm[1] === '@' ? [lm.slice(2)] : [lm[0] + lm[1], lm[2] + lm[3]]),
cg = $el.find('.cg-wrap').data('chessground');
cg.set({
fen: data.fen,
lastMove
});
const turnColor = fenColor(data.fen);
const renderClock = (time, color) => {
if (!isNaN(time)) $el.find('.mini-game__clock--' + color).clock('set', {
time,
pause: color != turnColor
});
};
renderClock(data.wc, 'white');
renderClock(data.bc, 'black');
},
finish(node, win) {
['white', 'black'].forEach(color =>
$(node).find('.mini-game__clock--' + color).each(function() {
$(this).clock('destroy');
}).replaceWith(`<span class="mini-game__result">${win ? (win == color[0] ? 1 : 0) : '½'}</span>`)
);
}
}
})();
$(function() {
if (lichess.analyse) LichessAnalyse.boot(lichess.analyse);
else if (lichess.user_analysis) startUserAnalysis(lichess.user_analysis);
@ -862,43 +772,6 @@
};
})());
lichess.widget("clock", {
_create: function() {
this.target = this.options.time * 1000 + Date.now();
if (!this.options.pause) this.interval = setInterval(this.render.bind(this), 1000);
this.render();
},
set: function(opts) {
this.options = opts;
this.target = this.options.time * 1000 + Date.now();
this.render();
clearInterval(this.interval);
if (!opts.pause) this.interval = setInterval(this.render.bind(this), 1000);
},
render: function() {
if (document.body.contains(this.element[0])) {
this.element.text(this.formatMs(this.target - Date.now()));
this.element.toggleClass('clock--run', !this.options.pause);
} else clearInterval(this.interval);
},
pad: function(x) {
return (x < 10 ? '0' : '') + x;
},
formatMs: function(msTime) {
const date = new Date(Math.max(0, msTime + 500)),
hours = date.getUTCHours(),
minutes = date.getUTCMinutes(),
seconds = date.getUTCSeconds();
return hours > 0 ?
hours + ':' + this.pad(minutes) + ':' + this.pad(seconds) :
minutes + ':' + this.pad(seconds);
}
});
$(function() {
lichess.pubsub.on('content_loaded', lichess.miniBoard.initAll);
lichess.pubsub.on('content_loaded', lichess.miniGame.initAll);

View File

@ -1,26 +1,3 @@
function parseFen($elem) {
$elem.each(function() {
var $this = $(this).removeClass('parse-fen');
var lm = $this.data('lastmove');
var color = $this.data('color');
var ground = $this.data('chessground');
var config = {
coordinates: false,
resizable: false,
drawable: { enabled: false, visible: false },
viewOnly: true,
fen: $this.data('fen'),
lastMove: lm && [lm[0] + lm[1], lm[2] + lm[3]]
};
if (color) config.orientation = color;
if (ground) ground.set(config);
else {
this.innerHTML = '<div class="cg-wrap"></div>';
$this.data('chessground', Chessground(this.firstChild, config));
}
});
}
function resize() {
var el = document.querySelector('#featured-game');
if (el.offsetHeight > window.innerHeight)
@ -29,19 +6,18 @@ function resize() {
$(function() {
var $featured = $('#featured-game');
var board = function() {
return $featured.find('.mini-board');
};
parseFen(board());
if (!window.EventSource) return;
const findGame = () => document.getElementsByClassName('mini-game').item(0);
const setup = () => lichess.miniGame.init(findGame());
setup();
var source = new EventSource($('body').data('stream-url'));
source.addEventListener('message', function(e) {
var data = JSON.parse(e.data);
if (data.t == "featured") {
$featured.html(data.d.html).find('a').attr('target', '_blank');
parseFen(board());
} else if (data.t == "fen") {
parseFen(board().data("fen", data.d.fen).data("lastmove", data.d.lm));
const msg = JSON.parse(e.data);
if (msg.t == "featured") {
$featured.html(msg.d.html).find('a').attr('target', '_blank');
setup();
} else if (msg.t == "fen") {
lichess.miniGame.update(findGame(), msg.d);
}
}, false);
resize();

View File

@ -235,7 +235,7 @@ lichess.loadCss = url => {
lichess.loadCssPath = key =>
lichess.loadCss(`css/${key}.${$('body').data('theme')}.${$('body').data('dev') ? 'dev' : 'min'}.css`);
lichess.jsModule = name =>
lichess.jsModule = name =>
`compiled/lichess.${name}${$('body').data('dev') ? '' : '.min'}.js`;
lichess.loadScript = (url, opts) =>
@ -404,3 +404,130 @@ $.modal.close = function() {
$(this).remove();
});
};
lichess.miniBoard = {
initAll() {
Array.from(document.getElementsByClassName('mini-board--init')).forEach(lichess.miniBoard.init);
},
init(node) {
if (!window.Chessground) return setTimeout(() => lichess.miniBoard.init(node), 500);
const $el = $(node).removeClass('mini-board--init'),
[fen, orientation, lm] = $el.data('state').split(',');
$el.data('chessground', Chessground(node, {
orientation,
coordinates: false,
viewOnly: !node.getAttribute('data-playable'),
resizable: false,
fen,
lastMove: lm && (lm[1] === '@' ? [lm.slice(2)] : [lm[0] + lm[1], lm[2] + lm[3]]),
drawable: {
enabled: false,
visible: false
}
}));
}
};
lichess.miniGame = (() => {
const fenColor = fen => fen.indexOf(' b') > 0 ? 'black' : 'white';
return {
init(node, data) {
const [fen, orientation, lm] = ((typeof data == 'string' && data) || node.getAttribute('data-state')).split(','),
config = {
coordinates: false,
viewOnly: true,
resizable: false,
fen,
orientation,
lastMove: lm && (lm[1] === '@' ? [lm.slice(2)] : [lm[0] + lm[1], lm[2] + lm[3]]),
drawable: {
enabled: false,
visible: false
}
},
$el = $(node).removeClass('mini-game--init'),
$cg = $el.find('.cg-wrap'),
turnColor = fenColor(fen);
$cg.data('chessground', Chessground($cg[0], config));
['white', 'black'].forEach(color =>
$el.find('.mini-game__clock--' + color).each(function() {
$(this).clock({
time: parseInt(this.getAttribute('data-time')),
pause: color != turnColor
});
})
);
return node.getAttribute('data-live');
},
initAll() {
const nodes = Array.from(document.getElementsByClassName('mini-game--init')),
ids = nodes.map(lichess.miniGame.init).filter(id => id);
if (ids.length) window.lichess.StrongSocket.firstConnect.then(send =>
send('startWatching', ids.join(' '))
);
},
update(node, data) {
const $el = $(node),
lm = data.lm,
lastMove = lm && (lm[1] === '@' ? [lm.slice(2)] : [lm[0] + lm[1], lm[2] + lm[3]]),
cg = $el.find('.cg-wrap').data('chessground');
cg.set({
fen: data.fen,
lastMove
});
const turnColor = fenColor(data.fen);
const renderClock = (time, color) => {
if (!isNaN(time)) $el.find('.mini-game__clock--' + color).clock('set', {
time,
pause: color != turnColor
});
};
renderClock(data.wc, 'white');
renderClock(data.bc, 'black');
},
finish(node, win) {
['white', 'black'].forEach(color =>
$(node).find('.mini-game__clock--' + color).each(function() {
$(this).clock('destroy');
}).replaceWith(`<span class="mini-game__result">${win ? (win == color[0] ? 1 : 0) : '½'}</span>`)
);
}
}
})();
lichess.widget("clock", {
_create: function() {
this.target = this.options.time * 1000 + Date.now();
if (!this.options.pause) this.interval = setInterval(this.render.bind(this), 1000);
this.render();
},
set: function(opts) {
this.options = opts;
this.target = this.options.time * 1000 + Date.now();
this.render();
clearInterval(this.interval);
if (!opts.pause) this.interval = setInterval(this.render.bind(this), 1000);
},
render: function() {
if (document.body.contains(this.element[0])) {
this.element.text(this.formatMs(this.target - Date.now()));
this.element.toggleClass('clock--run', !this.options.pause);
} else clearInterval(this.interval);
},
pad: function(x) {
return (x < 10 ? '0' : '') + x;
},
formatMs: function(msTime) {
const date = new Date(Math.max(0, msTime + 500)),
hours = date.getUTCHours(),
minutes = date.getUTCMinutes(),
seconds = date.getUTCSeconds();
return hours > 0 ?
hours + ':' + this.pad(minutes) + ':' + this.pad(seconds) :
minutes + ':' + this.pad(seconds);
}
});