progress on game UI with mithril
This commit is contained in:
parent
7028225d05
commit
2a293bfc8a
|
@ -55,28 +55,18 @@ object Round extends LilaController with TheftPrevention {
|
|||
negotiate(
|
||||
html = pov.game.started.fold(
|
||||
PreventTheft(pov) {
|
||||
env.version(pov.gameId) zip
|
||||
pov.opponent.userId.??(UserRepo.isEngine) zip
|
||||
(pov.game.tournamentId ?? TournamentRepo.byId) zip
|
||||
(pov.game.tournamentId ?? TournamentRepo.byId) zip
|
||||
Env.game.crosstableApi(pov.game) zip
|
||||
(pov.game.hasChat optionFu {
|
||||
Env.chat.api.playerChat find pov.gameId map (_ forUser ctx.me)
|
||||
}) zip
|
||||
(pov.game.playable ?? env.takebacker.isAllowedByPrefs(pov.game)) map {
|
||||
case (((((v, engine), tour), crosstable), chat), takebackable) =>
|
||||
Ok(html.round.player(pov, v, engine,
|
||||
chat = chat, tour = tour, cross = crosstable, takebackable = takebackable))
|
||||
(pov.game.playable ?? env.takebacker.isAllowedByPrefs(pov.game)) flatMap {
|
||||
case ((tour, crosstable), takebackable) =>
|
||||
env.jsonView.playerJson(pov, ctx.pref, Env.api.version, ctx.me) map { data =>
|
||||
Ok(html.round.player(pov, data, tour = tour, cross = crosstable, takebackable = takebackable))
|
||||
}
|
||||
}
|
||||
},
|
||||
Redirect(routes.Setup.await(fullId)).fuccess
|
||||
),
|
||||
api = apiVersion => (Env.round version pov.gameId) zip
|
||||
(pov.game.hasChat optionFu {
|
||||
Env.chat.api.playerChat find pov.gameId map (_ forUser ctx.me)
|
||||
}) map {
|
||||
case (v, chat) =>
|
||||
Ok(Env.round.jsonView.playerJson(pov, v, ctx.pref, chat, apiVersion))
|
||||
}
|
||||
api = apiVersion => env.jsonView.playerJson(pov, ctx.pref, apiVersion, ctx.me) map { Ok(_) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -102,7 +92,7 @@ object Round extends LilaController with TheftPrevention {
|
|||
}
|
||||
},
|
||||
api = apiVersion => Env.round version pov.gameId map { v =>
|
||||
Ok(Env.round.jsonView.watcherJson(pov, v, tv = false, pref = ctx.pref))
|
||||
Ok(env.jsonView.watcherJson(pov, v, tv = false, pref = ctx.pref))
|
||||
})
|
||||
|
||||
private def join(pov: Pov)(implicit ctx: Context): Fu[Result] =
|
||||
|
|
|
@ -177,8 +177,8 @@ object Setup extends LilaController with TheftPrevention with play.api.http.Cont
|
|||
config => op(config)(ctx) flatMap {
|
||||
case (pov, call) => negotiate(
|
||||
html = fuccess(redirectPov(pov, call)),
|
||||
api = apiVersion => Env.round version pov.gameId map { v =>
|
||||
Created(Env.round.jsonView.playerJson(pov, v, ctx.pref, chat = none, apiVersion)) as JSON
|
||||
api = apiVersion => Env.round.jsonView.playerJson(pov, ctx.pref, apiVersion, ctx.me) map { data =>
|
||||
Created(data) as JSON
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,29 +1,32 @@
|
|||
@(pov: Pov, version: Int, engine: Boolean, chat: Option[lila.chat.MixedChat], tour: Option[lila.tournament.Tournament], cross: Option[lila.game.Crosstable], takebackable: Boolean)(implicit ctx: Context)
|
||||
@(pov: Pov, data: play.api.libs.json.JsObject, tour: Option[lila.tournament.Tournament], cross: Option[lila.game.Crosstable], takebackable: Boolean)(implicit ctx: Context)
|
||||
|
||||
@import pov._
|
||||
|
||||
@title = @{ s"${trans.play.str()} ${playerText(pov.opponent)} in $gameId" }
|
||||
|
||||
@moreJs = {
|
||||
@*
|
||||
@jsAt(s"compiled/lichess.round${isProd??(".min")}.js")
|
||||
*@
|
||||
@jsAt(s"compiled/lichess.round.js")
|
||||
@helper.javascriptRouter("roundRoutes")(
|
||||
routes.javascript.Auth.signup
|
||||
)(ctx.req)
|
||||
@embedJs {
|
||||
LichessRound(
|
||||
document.getElementById('lichess'),
|
||||
@Html(play.api.libs.json.Json.stringify(roundPlayerJsData(pov, version, ctx.pref, apiVersion))),
|
||||
roundRoutes.controllers,
|
||||
@Html(J.stringify(i18nJsObject(
|
||||
lichess = lichess || {};
|
||||
lichess.round = {
|
||||
data: @Html(play.api.libs.json.Json.stringify(data)),
|
||||
routes: roundRoutes.controllers,
|
||||
i18n: @Html(J.stringify(i18nJsObject(
|
||||
trans.premoveEnabledClickAnywhereToCancel)))
|
||||
);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@round.layout(
|
||||
title = title,
|
||||
side = views.html.game.side(pov, tour, withTourStanding = true),
|
||||
chat = chat.map(c => base.chat(c, trans.chatRoom.str())),
|
||||
chat = none,
|
||||
underchat = views.html.game.watchers().some,
|
||||
moreJs = moreJs,
|
||||
openGraph = povOpenGraph(pov)) {
|
||||
|
|
|
@ -42,5 +42,7 @@ signedJs = routes.Round.signedJs(pov.gameId).toString.some) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@*
|
||||
@embedJs("var _ld_ = " + roundPlayerJsData(pov, version, ctx.pref, apiVersion))
|
||||
*@
|
||||
}
|
||||
|
|
|
@ -3,15 +3,15 @@
|
|||
|
||||
mkdir -p public/compiled
|
||||
|
||||
cd ui/editor
|
||||
npm install
|
||||
gulp prod
|
||||
cd -
|
||||
# cd ui/editor
|
||||
# npm install
|
||||
# gulp prod
|
||||
# cd -
|
||||
|
||||
cd ui/puzzle
|
||||
npm install
|
||||
gulp prod
|
||||
cd -
|
||||
# cd ui/puzzle
|
||||
# npm install
|
||||
# gulp prod
|
||||
# cd -
|
||||
|
||||
for file in tv.js common.js big.js chart2.js user.js coordinate.js pgn4hacks.js; do
|
||||
orig=public/javascripts/$file
|
||||
|
|
|
@ -6,7 +6,7 @@ import reactivemongo.bson.BSONDocument
|
|||
import lila.db.Types.Coll
|
||||
import lila.user.{ User, UserRepo }
|
||||
|
||||
private[chat] final class ChatApi(
|
||||
final class ChatApi(
|
||||
coll: Coll,
|
||||
flood: lila.security.Flood,
|
||||
maxLinesPerChat: Int,
|
||||
|
|
|
@ -22,9 +22,10 @@ object PlayApp {
|
|||
enabled = enableScheduler && isServer,
|
||||
debug = loadConfig getBoolean "app.scheduler.debug")
|
||||
|
||||
def isDev = isMode(_.Dev)
|
||||
def isTest = isMode(_.Test)
|
||||
def isProd = isMode(_.Prod)
|
||||
lazy val isDev = isMode(_.Dev)
|
||||
lazy val isTest = isMode(_.Test)
|
||||
lazy val isProd = isMode(_.Prod) && !loadConfig.getBoolean("forcedev")
|
||||
def isServer = !isTest
|
||||
|
||||
def isMode(f: Mode.type => Mode.Mode) = withApp { _.mode == f(Mode) }
|
||||
}
|
||||
|
|
|
@ -44,7 +44,6 @@ object Event {
|
|||
case class Move(orig: Pos, dest: Pos, color: Color) extends Event {
|
||||
def typ = "move"
|
||||
def data = Json.obj(
|
||||
"type" -> "move",
|
||||
"from" -> orig.key,
|
||||
"to" -> dest.key,
|
||||
"color" -> color.name)
|
||||
|
|
|
@ -20,11 +20,13 @@ final class Env(
|
|||
aiPerfApi: lila.ai.AiPerfApi,
|
||||
crosstableApi: lila.game.CrosstableApi,
|
||||
lightUser: String => Option[lila.common.LightUser],
|
||||
userJsonView: lila.user.JsonView,
|
||||
uciMemo: lila.game.UciMemo,
|
||||
rematch960Cache: lila.memo.ExpireSetMemo,
|
||||
onStart: String => Unit,
|
||||
i18nKeys: lila.i18n.I18nKeys,
|
||||
prefApi: lila.pref.PrefApi,
|
||||
chatApi: lila.chat.ChatApi,
|
||||
historyApi: lila.history.HistoryApi,
|
||||
scheduler: lila.common.Scheduler) {
|
||||
|
||||
|
@ -153,7 +155,11 @@ final class Env(
|
|||
|
||||
private[round] def moretimeSeconds = Moretime.toSeconds
|
||||
|
||||
lazy val jsonView = new JsonView(AnimationDuration)
|
||||
lazy val jsonView = new JsonView(
|
||||
chatApi = chatApi,
|
||||
userJsonView = userJsonView,
|
||||
getVersion = version,
|
||||
baseAnimationDuration = AnimationDuration)
|
||||
|
||||
{
|
||||
import scala.concurrent.duration._
|
||||
|
@ -192,11 +198,13 @@ object Env {
|
|||
aiPerfApi = lila.ai.Env.current.aiPerfApi,
|
||||
crosstableApi = lila.game.Env.current.crosstableApi,
|
||||
lightUser = lila.user.Env.current.lightUser,
|
||||
userJsonView = lila.user.Env.current.jsonView,
|
||||
uciMemo = lila.game.Env.current.uciMemo,
|
||||
rematch960Cache = lila.game.Env.current.cached.rematch960,
|
||||
onStart = lila.game.Env.current.onStart,
|
||||
i18nKeys = lila.i18n.Env.current.keys,
|
||||
prefApi = lila.pref.Env.current.api,
|
||||
chatApi = lila.chat.Env.current.api,
|
||||
historyApi = lila.history.Env.current.api,
|
||||
scheduler = lila.common.PlayApp.scheduler)
|
||||
}
|
||||
|
|
|
@ -8,78 +8,90 @@ import play.api.libs.json._
|
|||
import lila.common.PimpedJson._
|
||||
import lila.game.{ Pov, Game, PerfPicker }
|
||||
import lila.pref.Pref
|
||||
import lila.user.{ User, UserRepo }
|
||||
|
||||
import chess.format.Forsyth
|
||||
import chess.{ Color, Clock }
|
||||
|
||||
final class JsonView(baseAnimationDuration: Duration) {
|
||||
final class JsonView(
|
||||
chatApi: lila.chat.ChatApi,
|
||||
userJsonView: lila.user.JsonView,
|
||||
getVersion: String => Fu[Int],
|
||||
baseAnimationDuration: Duration) {
|
||||
|
||||
def playerJson(pov: Pov, version: Int, pref: Pref, chat: Option[lila.chat.MixedChat], apiVersion: Int) = {
|
||||
import pov._
|
||||
Json.obj(
|
||||
"game" -> Json.obj(
|
||||
"id" -> gameId,
|
||||
"variant" -> game.variant.key,
|
||||
"speed" -> game.speed.key,
|
||||
"perf" -> PerfPicker.key(game),
|
||||
"rated" -> game.rated,
|
||||
"fen" -> (Forsyth >> game.toChess),
|
||||
"moves" -> game.pgnMoves.mkString(" "),
|
||||
"started" -> game.started,
|
||||
"finished" -> game.finishedOrAborted,
|
||||
"clock" -> game.hasClock,
|
||||
"clockRunning" -> game.isClockRunning,
|
||||
"player" -> game.turnColor.name,
|
||||
"turns" -> game.turns,
|
||||
"startedAtTurn" -> game.startedAtTurn,
|
||||
"lastMove" -> game.castleLastMoveTime.lastMoveString),
|
||||
"clock" -> game.clock.map(clockJson),
|
||||
"player" -> Json.obj(
|
||||
"id" -> playerId,
|
||||
"color" -> player.color.name,
|
||||
"version" -> version,
|
||||
"spectator" -> false,
|
||||
"isOfferingRematch" -> player.isOfferingRematch.option(true),
|
||||
"isOfferingDraw" -> player.isOfferingDraw.option(true),
|
||||
"isProposingTakeback" -> player.isProposingTakeback.option(true)
|
||||
).noNull,
|
||||
"opponent" -> Json.obj(
|
||||
"color" -> opponent.color.name,
|
||||
"ai" -> opponent.aiLevel,
|
||||
"userId" -> opponent.userId,
|
||||
"isOfferingRematch" -> opponent.isOfferingRematch.option(true),
|
||||
"isOfferingDraw" -> opponent.isOfferingDraw.option(true),
|
||||
"isProposingTakeback" -> opponent.isProposingTakeback.option(true)
|
||||
).noNull,
|
||||
"url" -> Json.obj(
|
||||
"pov" -> s"/$fullId",
|
||||
"socket" -> s"/$fullId/socket/v$apiVersion",
|
||||
"end" -> s"/$fullId/end",
|
||||
"table" -> s"/$fullId/table"
|
||||
),
|
||||
"pref" -> Json.obj(
|
||||
"animationDuration" -> animationDuration(pov, pref),
|
||||
"autoQueen" -> pref.autoQueen,
|
||||
"autoThreefold" -> pref.autoThreefold,
|
||||
"clockTenths" -> pref.clockTenths,
|
||||
"clockBar" -> pref.clockBar,
|
||||
"enablePremove" -> pref.premove
|
||||
),
|
||||
"chat" -> chat.map { c =>
|
||||
JsArray(c.lines map {
|
||||
case lila.chat.UserLine(username, text, _) => Json.obj(
|
||||
"u" -> username,
|
||||
"t" -> text)
|
||||
case lila.chat.PlayerLine(color, text) => Json.obj(
|
||||
"c" -> color.name,
|
||||
"t" -> text)
|
||||
})
|
||||
},
|
||||
"possibleMoves" -> possibleMoves(pov),
|
||||
"tournamentId" -> game.tournamentId,
|
||||
"poolId" -> game.poolId
|
||||
)
|
||||
}
|
||||
def playerJson(
|
||||
pov: Pov,
|
||||
pref: Pref,
|
||||
apiVersion: Int,
|
||||
playerUser: Option[User]): Fu[JsObject] =
|
||||
getVersion(pov.game.id) zip
|
||||
(pov.opponent.userId ?? UserRepo.byId) zip
|
||||
getChat(pov.game, playerUser) map {
|
||||
case ((version, opponentUser), chat) =>
|
||||
import pov._
|
||||
Json.obj(
|
||||
"game" -> Json.obj(
|
||||
"id" -> gameId,
|
||||
"variant" -> game.variant.key,
|
||||
"speed" -> game.speed.key,
|
||||
"perf" -> PerfPicker.key(game),
|
||||
"rated" -> game.rated,
|
||||
"fen" -> (Forsyth >> game.toChess),
|
||||
"moves" -> game.pgnMoves.mkString(" "),
|
||||
"started" -> game.started,
|
||||
"finished" -> game.finishedOrAborted,
|
||||
"clock" -> game.hasClock,
|
||||
"clockRunning" -> game.isClockRunning,
|
||||
"player" -> game.turnColor.name,
|
||||
"turns" -> game.turns,
|
||||
"startedAtTurn" -> game.startedAtTurn,
|
||||
"lastMove" -> game.castleLastMoveTime.lastMoveString),
|
||||
"clock" -> game.clock.map(clockJson),
|
||||
"player" -> Json.obj(
|
||||
"id" -> playerId,
|
||||
"color" -> player.color.name,
|
||||
"version" -> version,
|
||||
"spectator" -> false,
|
||||
"user" -> playerUser.map { userJsonView(_, true) },
|
||||
"isOfferingRematch" -> player.isOfferingRematch.option(true),
|
||||
"isOfferingDraw" -> player.isOfferingDraw.option(true),
|
||||
"isProposingTakeback" -> player.isProposingTakeback.option(true)
|
||||
).noNull,
|
||||
"opponent" -> Json.obj(
|
||||
"color" -> opponent.color.name,
|
||||
"ai" -> opponent.aiLevel,
|
||||
"user" -> opponentUser.map { userJsonView(_, true) },
|
||||
"isOfferingRematch" -> opponent.isOfferingRematch.option(true),
|
||||
"isOfferingDraw" -> opponent.isOfferingDraw.option(true),
|
||||
"isProposingTakeback" -> opponent.isProposingTakeback.option(true)
|
||||
).noNull,
|
||||
"url" -> Json.obj(
|
||||
"socket" -> s"/$fullId/socket/v$apiVersion"
|
||||
),
|
||||
"pref" -> Json.obj(
|
||||
"animationDuration" -> animationDuration(pov, pref),
|
||||
"highlight" -> pref.highlight,
|
||||
"destination" -> pref.destination,
|
||||
"autoQueen" -> pref.autoQueen,
|
||||
"autoThreefold" -> pref.autoThreefold,
|
||||
"clockTenths" -> pref.clockTenths,
|
||||
"clockBar" -> pref.clockBar,
|
||||
"enablePremove" -> pref.premove
|
||||
),
|
||||
"chat" -> chat.map { c =>
|
||||
JsArray(c.lines map {
|
||||
case lila.chat.UserLine(username, text, _) => Json.obj(
|
||||
"u" -> username,
|
||||
"t" -> text)
|
||||
case lila.chat.PlayerLine(color, text) => Json.obj(
|
||||
"c" -> color.name,
|
||||
"t" -> text)
|
||||
})
|
||||
},
|
||||
"possibleMoves" -> possibleMoves(pov),
|
||||
"tournamentId" -> game.tournamentId,
|
||||
"poolId" -> game.poolId)
|
||||
}
|
||||
|
||||
def watcherJson(pov: Pov, version: Int, tv: Boolean, pref: Pref) = {
|
||||
import pov._
|
||||
|
@ -121,6 +133,14 @@ final class JsonView(baseAnimationDuration: Duration) {
|
|||
)
|
||||
}
|
||||
|
||||
private def getChat(game: Game, forUser: Option[User]) = game.hasChat optionFu {
|
||||
chatApi.playerChat find game.id map (_ forUser forUser)
|
||||
}
|
||||
|
||||
private def getUsers(game: Game) = UserRepo.pair(
|
||||
game.whitePlayer.userId,
|
||||
game.blackPlayer.userId)
|
||||
|
||||
private def clockJson(clock: Clock) = Json.obj(
|
||||
"initial" -> clock.limit,
|
||||
"increment" -> clock.increment,
|
||||
|
|
|
@ -12,9 +12,6 @@ trait RoundHelper {
|
|||
|
||||
def moretimeSeconds = roundEnv.moretimeSeconds
|
||||
|
||||
def roundPlayerJsData(pov: Pov, version: Int, pref: Pref, apiVersion: Int) =
|
||||
roundEnv.jsonView.playerJson(pov, version, pref, chat = none, apiVersion = apiVersion)
|
||||
|
||||
def roundWatcherJsData(pov: Pov, version: Int, tv: Boolean, pref: Pref) =
|
||||
roundEnv.jsonView.watcherJson(pov, version, tv, pref)
|
||||
}
|
||||
|
|
|
@ -338,8 +338,7 @@ var storage = {
|
|||
}
|
||||
|
||||
// Start game
|
||||
var $game = $('div.lichess_game').orNot();
|
||||
if ($game && false) $game.game(_ld_);
|
||||
if (lichess.round) $('#lichess').game(lichess.round);
|
||||
|
||||
setTimeout(function() {
|
||||
if (lichess.socket === null) {
|
||||
|
@ -650,6 +649,23 @@ var storage = {
|
|||
$.widget("lichess.game", {
|
||||
|
||||
_init: function() {
|
||||
var cfg = this.options;
|
||||
lichess.socket = new lichess.StrongSocket(
|
||||
cfg.data.url.socket,
|
||||
cfg.data.player.version,
|
||||
{
|
||||
options: {
|
||||
name: "round"
|
||||
},
|
||||
params: {
|
||||
ran: "--ranph--",
|
||||
userTv: $('.user_tv').data('user-tv')
|
||||
},
|
||||
receive: function(t, d) { round.socketReceive(t, d); }
|
||||
});
|
||||
var round = LichessRound(this.element[0], cfg.data, cfg.routes, cfg.i18n, lichess.socket.send.bind(lichess.socket));
|
||||
},
|
||||
_old_init: function() {
|
||||
var self = this;
|
||||
self.$board = self.element.find("div.lichess_board");
|
||||
self.$table = self.element.find("div.lichess_table_wrap");
|
||||
|
|
|
@ -111,9 +111,15 @@ lichess.StrongSocket.prototype = {
|
|||
}
|
||||
self.scheduleConnect(self.options.pingMaxLag);
|
||||
},
|
||||
send: function(t, d) {
|
||||
send: function(t, d, o) {
|
||||
var self = this;
|
||||
var data = d || {};
|
||||
var data = d || {},
|
||||
options = o || {};
|
||||
if (options && options.ackable)
|
||||
self.ackableMessages.push({
|
||||
t: t,
|
||||
d: d
|
||||
});
|
||||
var message = JSON.stringify({
|
||||
t: t,
|
||||
d: data
|
||||
|
@ -126,11 +132,9 @@ lichess.StrongSocket.prototype = {
|
|||
}
|
||||
},
|
||||
sendAckable: function(t, d) {
|
||||
this.ackableMessages.push({
|
||||
t: t,
|
||||
d: d
|
||||
this.send(t, d, {
|
||||
ackable: true
|
||||
});
|
||||
this.send(t, d);
|
||||
},
|
||||
scheduleConnect: function(delay) {
|
||||
var self = this;
|
||||
|
@ -202,10 +206,12 @@ lichess.StrongSocket.prototype = {
|
|||
self.ackableMessages = [];
|
||||
break;
|
||||
default:
|
||||
var h = self.settings.events[m.t];
|
||||
if ($.isFunction(h)) h(m.d || null);
|
||||
else if (!self.options.ignoreUnknownMessages) {
|
||||
self.debug('Message not supported ' + JSON.stringify(m));
|
||||
if (!self.settings.receive || !self.settings.receive(m.t, m.d)) {
|
||||
var h = self.settings.events[m.t];
|
||||
if ($.isFunction(h)) h(m.d || null);
|
||||
else if (!self.options.ignoreUnknownMessages) {
|
||||
self.debug('Message not supported ' + JSON.stringify(m));
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
"watchify": "^1.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"chessground": "git://github.com/ornicar/chessground#4821c08",
|
||||
"chessground": "git://github.com/ornicar/chessground.git",
|
||||
"lodash-node": "^2.4.1",
|
||||
"mithril": "git://github.com/lhorie/mithril.js.git#c16350de5ab64118"
|
||||
"mithril": "^0.1.22"
|
||||
}
|
||||
}
|
||||
|
|
28
ui/round/src/clock/ctrl.js
Normal file
28
ui/round/src/clock/ctrl.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
module.exports = function(data) {
|
||||
|
||||
var lastUpdate;
|
||||
|
||||
this.data = data;
|
||||
this.data.barTime = Math.max(this.data.initial, 2) + 5 * this.data.increment;
|
||||
|
||||
function setLastUpdate() {
|
||||
lastUpdate = {
|
||||
white: data.white,
|
||||
black: data.black,
|
||||
at: new Date()
|
||||
};
|
||||
}
|
||||
setLastUpdate();
|
||||
|
||||
this.update = function(white, black) {
|
||||
this.data.white = white;
|
||||
this.data.black = black;
|
||||
setLastUpdate();
|
||||
};
|
||||
|
||||
this.tick = function(color) {
|
||||
m.startComputation();
|
||||
this.data[color] = lastUpdate[color] - (new Date() - lastUpdate.at) / 1000;
|
||||
m.endComputation();
|
||||
}.bind(this);
|
||||
}
|
44
ui/round/src/clock/view.js
Normal file
44
ui/round/src/clock/view.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
var classSet = require('chessground').util.classSet;
|
||||
|
||||
function prefixInteger(num, length) {
|
||||
return (num / Math.pow(10, length)).toFixed(length).substr(2);
|
||||
}
|
||||
|
||||
function bold(x) {
|
||||
return '<b>' + x + '</b>';
|
||||
}
|
||||
|
||||
function formatClockTime(ctrl, time) {
|
||||
var date = new Date(time);
|
||||
var minutes = prefixInteger(date.getUTCMinutes(), 2);
|
||||
var seconds = prefixInteger(date.getSeconds(), 2);
|
||||
if (ctrl.data.showTenths && time < 10000) {
|
||||
tenths = Math.floor(date.getMilliseconds() / 100);
|
||||
return bold(minutes) + ':' + bold(seconds) + '<span>.' + bold(tenths) + '</span>';
|
||||
} else if (time >= 3600000) {
|
||||
var hours = prefixInteger(date.getUTCHours(), 2);
|
||||
return bold(hours) + ':' + bold(minutes) + ':' + bold(seconds);
|
||||
} else {
|
||||
return bold(minutes) + ':' + bold(seconds);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function(ctrl, color, position, runningColor) {
|
||||
var time = ctrl.data[color];
|
||||
return m('div', {
|
||||
class: 'clock clock_' + color + ' clock_' + position + ' ' + classSet({
|
||||
'outoftime': !time,
|
||||
'running': runningColor === color,
|
||||
'emerg': time < ctrl.data.emerg
|
||||
})
|
||||
}, [
|
||||
ctrl.data.showBar ? m('div.bar',
|
||||
m('span', {
|
||||
style: {
|
||||
width: Math.max(0, Math.min(100, (time / ctrl.data.barTime) * 100)) + 'px'
|
||||
}
|
||||
})
|
||||
) : null,
|
||||
m('div.time', m.trust(formatClockTime(ctrl, time * 1000)))
|
||||
]);
|
||||
}
|
|
@ -4,21 +4,41 @@ var chessground = require('chessground');
|
|||
var data = require('./data');
|
||||
var round = require('./round');
|
||||
var socket = require('./socket');
|
||||
var clockCtrl = require('./clock/ctrl');
|
||||
var util = require('./util');
|
||||
|
||||
module.exports = function(cfg, router, i18n) {
|
||||
module.exports = function(cfg, router, i18n, socketSend) {
|
||||
|
||||
this.data = data(cfg);
|
||||
|
||||
this.socket = new socket(socketSend, this);
|
||||
|
||||
this.userMove = function(orig, dest) {
|
||||
var move = {
|
||||
from: orig,
|
||||
to: dest,
|
||||
};
|
||||
if (this.clock) move.lag = Math.round(lichess.socket.averageLag);
|
||||
this.socket.send('move', move, {
|
||||
ackable: true
|
||||
});
|
||||
}.bind(this);
|
||||
|
||||
this.chessground = new chessground.controller({
|
||||
fen: cfg.game.fen,
|
||||
orientation: this.data.player.color,
|
||||
turnColor: this.data.game.player,
|
||||
lastMove: util.str2move(this.data.game.lastMove),
|
||||
highlight: {
|
||||
lastMove: this.data.pref.highlight,
|
||||
check: this.data.pref.highlight,
|
||||
dragOver: true
|
||||
},
|
||||
movable: {
|
||||
free: false,
|
||||
color: round.isPlayerPlaying(this.data) ? this.data.player.color : null,
|
||||
dests: round.parsePossibleMoves(this.data.possibleMoves),
|
||||
showDests: this.data.pref.destination,
|
||||
events: {
|
||||
after: this.userMove
|
||||
},
|
||||
|
@ -28,24 +48,25 @@ module.exports = function(cfg, router, i18n) {
|
|||
duration: this.data.pref.animationDuration
|
||||
},
|
||||
premovable: {
|
||||
enabled: this.data.pref.enablePremove
|
||||
enabled: this.data.pref.enablePremove,
|
||||
showDests: this.data.pref.destination
|
||||
}
|
||||
});
|
||||
|
||||
this.socket = window.lichess.socket = socket.make(this.data);
|
||||
this.clock = this.data.clock ? new clockCtrl(this.data.clock) : false;
|
||||
|
||||
this.userMove = function(orig, dest) {
|
||||
console.log('userMove', [orig, dest]);
|
||||
this.isClockRunning = function() {
|
||||
return !this.data.game.finished && ((this.data.game.turns - this.data.game.startedAtTurn) > 1 || this.data.game.clockRunning);
|
||||
}.bind(this);
|
||||
|
||||
this.clockTick = function() {
|
||||
if (this.isClockRunning()) this.clock.tick(this.data.game.player);
|
||||
}.bind(this);
|
||||
|
||||
if (this.clock) setInterval(this.clockTick, 100);
|
||||
|
||||
this.router = router;
|
||||
|
||||
this.costly = function(cell) {
|
||||
return (this.chessground.data.draggable.current.orig || this.chessground.data.animation.current.start) ? {
|
||||
subtree: 'retain'
|
||||
} : cell();
|
||||
}.bind(this);
|
||||
|
||||
this.trans = function() {
|
||||
var str = i18n[arguments[0]]
|
||||
Array.prototype.slice.call(arguments, 1).forEach(function(arg) {
|
||||
|
|
|
@ -7,5 +7,10 @@ module.exports = function(cfg) {
|
|||
|
||||
merge(data, cfg);
|
||||
|
||||
if (data.clock) {
|
||||
data.clock.showTenths = data.pref.clockTenths;
|
||||
data.clock.showBar = data.pref.clockBar;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
var ctrl = require('./ctrl');
|
||||
var view = require('./view');
|
||||
|
||||
module.exports = function(element, config, router, i18n) {
|
||||
var controller = new ctrl(config, router, i18n);
|
||||
module.exports = function(element, config, router, i18n, socketSend) {
|
||||
|
||||
var controller = new ctrl(config, router, i18n, socketSend);
|
||||
|
||||
m.module(element, {
|
||||
controller: function () { return controller; },
|
||||
view: view
|
||||
});
|
||||
|
||||
return {
|
||||
socketReceive: controller.socket.receive
|
||||
};
|
||||
};
|
||||
|
|
|
@ -1,17 +1,77 @@
|
|||
function make(data) {
|
||||
var m = require('mithril');
|
||||
var round = require('./round');
|
||||
var ground = require('chessground');
|
||||
|
||||
return new lichess.StrongSocket(data.url.socket, data.player.version, {
|
||||
options: {
|
||||
name: "game"
|
||||
module.exports = function(send, ctrl) {
|
||||
|
||||
this.send = send;
|
||||
|
||||
var handlers = {
|
||||
possibleMoves: function(o) {
|
||||
ctrl.chessground.reconfigure({
|
||||
movable: {
|
||||
dests: round.parsePossibleMoves(o)
|
||||
}
|
||||
});
|
||||
},
|
||||
params: {
|
||||
ran: "--ranph--",
|
||||
userTv: $('.user_tv').data('user-tv')
|
||||
state: function(o) {
|
||||
ctrl.chessground.reconfigure({
|
||||
turnColor: o.color
|
||||
});
|
||||
ctrl.data.game.player = o.color;
|
||||
ctrl.data.game.turns = o.turns;
|
||||
},
|
||||
events: {}
|
||||
});
|
||||
move: function(o) {
|
||||
ctrl.chessground.apiMove(o.from, o.to);
|
||||
},
|
||||
premove: function() {
|
||||
ctrl.chessground.playPremove();
|
||||
},
|
||||
castling: function(o) {
|
||||
var pieces = {};
|
||||
pieces[o.king[0]] = null;
|
||||
pieces[o.king[1]] = {
|
||||
role: 'king',
|
||||
color: o.color
|
||||
};
|
||||
pieces[o.rook[0]] = null;
|
||||
pieces[o.rook[1]] = {
|
||||
role: 'rook',
|
||||
color: o.color
|
||||
};
|
||||
ctrl.chessground.setPieces(pieces);
|
||||
},
|
||||
check: function(o) {
|
||||
ctrl.chessground.reconfigure({
|
||||
check: o
|
||||
});
|
||||
},
|
||||
enpassant: function(o) {
|
||||
var pieces = {};
|
||||
pieces.o = null;
|
||||
ctrl.chessground.setPieces(pieces);
|
||||
},
|
||||
// still used by rematch join
|
||||
redirect: function(o) {
|
||||
setTimeout(function() {
|
||||
lichess.hasToReload = true;
|
||||
$.redirect(o);
|
||||
}, 400);
|
||||
},
|
||||
threefoldRepetition: function() {
|
||||
// ???
|
||||
},
|
||||
clock: function(o) {
|
||||
if (ctrl.clock) ctrl.clock.update(o.white, o.black);
|
||||
}
|
||||
};
|
||||
|
||||
this.receive = function(type, data) {
|
||||
console.log(type, data);
|
||||
if (handlers[type]) {
|
||||
handlers[type](data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}.bind(this);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
make: make
|
||||
};
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
var partial = require('lodash-node/modern/functions/partial');
|
||||
var map = require('lodash-node/modern/collections/map');
|
||||
var chessground = require('chessground');
|
||||
var opposite = chessground.util.opposite;
|
||||
var classSet = chessground.util.classSet;
|
||||
var partial = chessground.util.partial;
|
||||
var clockView = require('./clock/view');
|
||||
var m = require('mithril');
|
||||
|
||||
module.exports = function(ctrl) {
|
||||
var clockRunningColor = ctrl.isClockRunning() ? ctrl.data.game.player : null;
|
||||
return m('div', {
|
||||
class: 'lichess_game clearfix not_spectator pov_' + ctrl.data.player.color
|
||||
}, [
|
||||
|
@ -11,6 +15,17 @@ module.exports = function(ctrl) {
|
|||
m('div.lichess_board_wrap', ctrl.data.blindMode ? null : [
|
||||
m('div.lichess_board.' + ctrl.data.game.variant, chessground.view(ctrl.chessground)),
|
||||
m('div#premove_alert', ctrl.trans('premoveEnabledClickAnywhereToCancel'))
|
||||
])
|
||||
]),
|
||||
m('div.lichess_ground',
|
||||
m('div.lichess_table_wrap', [
|
||||
(ctrl.clock && !ctrl.data.blindMode) ? clockView(ctrl.clock, opposite(ctrl.data.player.color), "top", clockRunningColor) : null,
|
||||
m('div', {
|
||||
class: 'lichess_table onbg ' + classSet({
|
||||
'table_with_clock': ctrl.clock,
|
||||
'finished': ctrl.data.game.finished
|
||||
})
|
||||
}), (ctrl.clock && !ctrl.data.blindMode) ? clockView(ctrl.clock, ctrl.data.player.color, "bottom", clockRunningColor) : null,
|
||||
])
|
||||
)
|
||||
]);
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue