more ui rewrite
parent
327e16a177
commit
9176439660
|
@ -2,7 +2,6 @@ package views.html.base
|
|||
|
||||
import controllers.routes
|
||||
import play.api.i18n.Lang
|
||||
import play.api.libs.json.Json
|
||||
|
||||
import lila.api.{ AnnounceStore, Context }
|
||||
import lila.app.templating.Environment._
|
||||
|
|
|
@ -23,7 +23,7 @@ object home {
|
|||
moreJs = frag(
|
||||
jsModule("lobby", defer = true),
|
||||
embedJsUnsafe(
|
||||
s"""lichess=window.lichess||{};customWS=true;lichess_lobby=${safeJsonValue(
|
||||
s"""window.lichess.load.then(()=>window.LichessLobby(${safeJsonValue(
|
||||
Json.obj(
|
||||
"data" -> data,
|
||||
"playban" -> playban.map { pb =>
|
||||
|
@ -34,7 +34,7 @@ object home {
|
|||
},
|
||||
"i18n" -> i18nJsObject(i18nKeys)
|
||||
)
|
||||
)}"""
|
||||
)}))"""
|
||||
)
|
||||
),
|
||||
moreCss = cssTag("lobby"),
|
||||
|
|
|
@ -15,7 +15,7 @@ object msg {
|
|||
moreJs = frag(
|
||||
jsModule("msg"),
|
||||
embedJsUnsafe(
|
||||
s"""$$(() =>LichessMsg(document.querySelector('.msg-app'), ${safeJsonValue(
|
||||
s"""window.lichess.load.then(()=>LichessMsg(${safeJsonValue(
|
||||
Json.obj(
|
||||
"data" -> json,
|
||||
"i18n" -> jsI18n
|
||||
|
|
|
@ -29,7 +29,7 @@ interface Lichess {
|
|||
unload: {
|
||||
expected: boolean;
|
||||
};
|
||||
redirect(o: string | { url: string, cookie: Cookie }): void;
|
||||
redirect(o: RedirectTo): void;
|
||||
reload(): void;
|
||||
escapeHtml(str: string): string;
|
||||
announce(d: LichessAnnouncement): void;
|
||||
|
@ -55,7 +55,7 @@ interface Lichess {
|
|||
|
||||
// socket.js
|
||||
StrongSocket: {
|
||||
(url: string, version: number | false, cfg: any): any;
|
||||
new(url: string, version: number | false, cfg: any): any;
|
||||
firstConnect: Promise<(tpe: string, data: any) => void>
|
||||
}
|
||||
|
||||
|
@ -88,6 +88,8 @@ interface Lichess {
|
|||
}
|
||||
}
|
||||
|
||||
type RedirectTo = string | { url: string, cookie: Cookie };
|
||||
|
||||
interface SoundBoxI {
|
||||
loadOggOrMp3(name: string, path: string): void;
|
||||
play(name: string): void;
|
||||
|
|
|
@ -3,7 +3,7 @@ import { rollupProject } from '@build/rollupProject';
|
|||
export default rollupProject({
|
||||
main: {
|
||||
name: 'LichessLobby',
|
||||
input: 'src/main.ts',
|
||||
input: 'src/boot.ts',
|
||||
output: 'lobby',
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
export default function boot(cfg, element) {
|
||||
cfg.pools = [ // mirrors modules/pool/src/main/PoolList.scala
|
||||
import { LobbyOpts } from './interfaces';
|
||||
import main from './main';
|
||||
|
||||
export default function LichessLobby(opts: LobbyOpts) {
|
||||
|
||||
opts.element = document.querySelector('.lobby__app') as HTMLElement;
|
||||
opts.pools = [ // mirrors modules/pool/src/main/PoolList.scala
|
||||
{ id: "1+0", lim: 1, inc: 0, perf: "Bullet" },
|
||||
{ id: "2+1", lim: 2, inc: 1, perf: "Bullet" },
|
||||
{ id: "3+0", lim: 3, inc: 0, perf: "Blitz" },
|
||||
|
@ -12,9 +17,8 @@ export default function boot(cfg, element) {
|
|||
{ id: "30+0", lim: 30, inc: 0, perf: "Classical" },
|
||||
{ id: "30+20", lim: 30, inc: 20, perf: "Classical" }
|
||||
];
|
||||
const li = window.lichess;
|
||||
let lobby;
|
||||
const nbRoundSpread = spreadNumber(
|
||||
const li = window.lichess,
|
||||
nbRoundSpread = spreadNumber(
|
||||
document.querySelector('#nb_games_in_play > strong') as HTMLElement,
|
||||
8),
|
||||
nbUserSpread = spreadNumber(
|
||||
|
@ -24,12 +28,11 @@ export default function boot(cfg, element) {
|
|||
const match = RegExp('[?&]' + name + '=([^&]*)').exec(location.search);
|
||||
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
|
||||
};
|
||||
li.socket = li.StrongSocket(
|
||||
let lobby: any;
|
||||
li.socket = new li.StrongSocket(
|
||||
'/lobby/socket/v5',
|
||||
false, {
|
||||
receive(t: string, d: any) {
|
||||
lobby.socketReceive(t, d);
|
||||
},
|
||||
receive(t: string, d: any) { lobby.socketReceive(t, d) },
|
||||
events: {
|
||||
n(_: string, msg: any) {
|
||||
nbUserSpread(msg.d);
|
||||
|
@ -44,16 +47,16 @@ export default function boot(cfg, element) {
|
|||
}
|
||||
});
|
||||
},
|
||||
featured(o) {
|
||||
featured(o: { html: string}) {
|
||||
$('.lobby__tv').html(o.html);
|
||||
li.pubsub.emit('content_loaded');
|
||||
},
|
||||
redirect(e) {
|
||||
redirect(e: RedirectTo) {
|
||||
lobby.leavePool();
|
||||
lobby.setRedirecting();
|
||||
li.redirect(e);
|
||||
},
|
||||
fen(e) {
|
||||
fen(e: any) {
|
||||
lobby.gameActivity(e.id);
|
||||
}
|
||||
}
|
||||
|
@ -66,16 +69,15 @@ export default function boot(cfg, element) {
|
|||
history.replaceState(null, '', '/');
|
||||
});
|
||||
|
||||
cfg.blindMode = $('body').hasClass('blind-mode');
|
||||
cfg.trans = li.trans(cfg.i18n);
|
||||
cfg.socketSend = li.socket.send;
|
||||
cfg.element = element;
|
||||
lobby = window.LichessLobby.start(cfg);
|
||||
opts.blindMode = $('body').hasClass('blind-mode');
|
||||
opts.trans = li.trans(opts.i18n);
|
||||
opts.socketSend = li.socket.send;
|
||||
lobby = main(opts);
|
||||
|
||||
const $startButtons = $('.lobby__start'),
|
||||
clickEvent = cfg.blindMode ? 'click' : 'mousedown';
|
||||
clickEvent = opts.blindMode ? 'click' : 'mousedown';
|
||||
|
||||
$startButtons.find('a:not(.disabled)').on(clickEvent, function() {
|
||||
$startButtons.find('a:not(.disabled)').on(clickEvent, function(this: HTMLElement) {
|
||||
$(this).addClass('active').siblings().removeClass('active');
|
||||
li.loadCssPath('lobby.setup');
|
||||
lobby.leavePool();
|
||||
|
@ -100,7 +102,7 @@ export default function boot(cfg, element) {
|
|||
if (['#ai', '#friend', '#hook'].includes(location.hash)) {
|
||||
$startButtons
|
||||
.find('.config_' + location.hash.replace('#', ''))
|
||||
.each(function() {
|
||||
.each(function(this: HTMLElement) {
|
||||
$(this).attr("href", $(this).attr("href") + location.search);
|
||||
}).trigger(clickEvent);
|
||||
|
||||
|
@ -113,7 +115,7 @@ export default function boot(cfg, element) {
|
|||
|
||||
history.replaceState(null, '', '/');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function spreadNumber(el: HTMLElement, nbSteps: number) {
|
||||
let previous: number, displayed: string;
|
||||
|
|
|
@ -44,7 +44,7 @@ export default class Filter {
|
|||
filter = (hooks: Hook[]): Filtered => {
|
||||
if (!this.data) return { visible: hooks, hidden: 0 };
|
||||
const f = this.data.filter,
|
||||
ratingRange = f.ratingRange && f.ratingRange.split('-').map(r => parseInt(r, 10)),
|
||||
ratingRange = f.ratingRange && f.ratingRange.split('-').map((r: string) => parseInt(r, 10)),
|
||||
seen: string[] = [],
|
||||
visible: Hook[] = [];
|
||||
let variant: string, hidden = 0;
|
||||
|
|
|
@ -10,9 +10,8 @@ export const patch = init([klass, attributes]);
|
|||
|
||||
import makeCtrl from './ctrl';
|
||||
import view from './view/main';
|
||||
import boot from './boot';
|
||||
|
||||
export function start(opts: LobbyOpts) {
|
||||
export default function main(opts: LobbyOpts) {
|
||||
|
||||
let vnode: VNode, ctrl: LobbyController;
|
||||
|
||||
|
@ -44,7 +43,3 @@ export function start(opts: LobbyOpts) {
|
|||
// that's for the rest of lichess to access chessground
|
||||
// without having to include it a second time
|
||||
window.Chessground = Chessground;
|
||||
|
||||
window.lichess.load.then(() =>
|
||||
boot(window['lichess_lobby'], document.querySelector('.lobby__app'))
|
||||
);
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
{
|
||||
"extends": "../tsconfig.base.json",
|
||||
"include": ["src/**/*.ts"],
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": false,
|
||||
"noImplicitThis": false,
|
||||
"lib": ["DOM", "ES2016", "DOM.iterable"]
|
||||
"noImplicitAny": false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,11 @@ import { MsgOpts } from './interfaces'
|
|||
import { upgradeData } from './network'
|
||||
import MsgCtrl from './ctrl';
|
||||
|
||||
export default function LichessMsg(element: HTMLElement, opts: MsgOpts) {
|
||||
export default function LichessMsg(opts: MsgOpts) {
|
||||
|
||||
const patch = init([klass, attributes]);
|
||||
|
||||
const appHeight = () => document.body.style.setProperty('--app-height', `${window.innerHeight}px`);
|
||||
const element = document.querySelector('.msg-app') as HTMLElement,
|
||||
patch = init([klass, attributes]),
|
||||
appHeight = () => document.body.style.setProperty('--app-height', `${window.innerHeight}px`);
|
||||
window.addEventListener('resize', appHeight);
|
||||
appHeight();
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ export default function(opts: RoundOpts): void {
|
|||
data: RoundData = opts.data;
|
||||
let round: RoundApi;
|
||||
if (data.tournament) $('body').data('tournament-id', data.tournament.id);
|
||||
li.socket = li.StrongSocket(
|
||||
li.socket = new li.StrongSocket(
|
||||
data.url.socket,
|
||||
data.player.version, {
|
||||
params: { userTv: data.userTv && data.userTv.id },
|
||||
|
|
|
@ -18,7 +18,7 @@ function startTournament(cfg) {
|
|||
const element = document.querySelector('main.tour') as HTMLElement;
|
||||
$('body').data('tournament-id', cfg.data.id);
|
||||
let tournament;
|
||||
window.lichess.socket = StrongSocket(
|
||||
window.lichess.socket = new StrongSocket(
|
||||
`/tournament/${cfg.data.id}/socket/v5`, cfg.data.socketVersion, {
|
||||
receive: (t, d) => tournament.socketReceive(t, d)
|
||||
});
|
||||
|
@ -28,7 +28,7 @@ function startTournament(cfg) {
|
|||
}
|
||||
|
||||
function startTeam(cfg) {
|
||||
window.lichess.socket = StrongSocket('/team/' + cfg.id, cfg.socketVersion);
|
||||
window.lichess.socket = new StrongSocket('/team/' + cfg.id, cfg.socketVersion);
|
||||
cfg.chat && makeChat(cfg.chat);
|
||||
$('#team-subscribe').on('change', function(this: HTMLInputElement) {
|
||||
const v = this.checked;
|
||||
|
@ -42,7 +42,7 @@ function startUserAnalysis(cfg) {
|
|||
var analyse;
|
||||
cfg.initialPly = 'url';
|
||||
cfg.trans = trans(cfg.i18n);
|
||||
window.lichess.socket = StrongSocket('/analysis/socket/v5', false, {
|
||||
window.lichess.socket = new StrongSocket('/analysis/socket/v5', false, {
|
||||
receive: (t, d) => analyse.socketReceive(t, d)
|
||||
});
|
||||
cfg.socketSend = window.lichess.socket.send;
|
||||
|
@ -53,7 +53,7 @@ function startUserAnalysis(cfg) {
|
|||
function startStudy(cfg) {
|
||||
var analyse;
|
||||
cfg.initialPly = 'url';
|
||||
window.lichess.socket = StrongSocket(cfg.socketUrl, cfg.socketVersion, {
|
||||
window.lichess.socket = new StrongSocket(cfg.socketUrl, cfg.socketVersion, {
|
||||
receive: (t, d) => analyse.socketReceive(t, d)
|
||||
});
|
||||
cfg.socketSend = window.lichess.socket.send;
|
||||
|
@ -64,7 +64,7 @@ function startStudy(cfg) {
|
|||
function startPractice(cfg) {
|
||||
var analyse;
|
||||
cfg.trans = trans(cfg.i18n);
|
||||
window.lichess.socket = StrongSocket('/analysis/socket/v5', false, {
|
||||
window.lichess.socket = new StrongSocket('/analysis/socket/v5', false, {
|
||||
receive: (t, d) => analyse.socketReceive(t, d)
|
||||
});
|
||||
cfg.socketSend = window.lichess.socket.send;
|
||||
|
@ -74,7 +74,7 @@ function startPractice(cfg) {
|
|||
function startRelay(cfg) {
|
||||
var analyse;
|
||||
cfg.initialPly = 'url';
|
||||
window.lichess.socket = StrongSocket(cfg.socketUrl, cfg.socketVersion, {
|
||||
window.lichess.socket = new StrongSocket(cfg.socketUrl, cfg.socketVersion, {
|
||||
receive: (t, d) => analyse.socketReceive(t, d)
|
||||
});
|
||||
cfg.socketSend = window.lichess.socket.send;
|
||||
|
|
|
@ -42,37 +42,6 @@ interface Settings {
|
|||
options: Options;
|
||||
}
|
||||
|
||||
|
||||
class Ackable {
|
||||
|
||||
currentId = 1; // increment with each ackable message sent
|
||||
messages: MsgAck[] = [];
|
||||
|
||||
constructor(readonly send: Send) {
|
||||
setInterval(this.resend, 1200);
|
||||
}
|
||||
|
||||
resend = () => {
|
||||
const resendCutoff = performance.now() - 2500;
|
||||
this.messages.forEach(m => {
|
||||
if (m.at < resendCutoff) this.send(m.t, m.d);
|
||||
});
|
||||
}
|
||||
|
||||
register = (t: Tpe, d: Payload) => {
|
||||
d.a = this.currentId++;
|
||||
this.messages.push({
|
||||
t: t,
|
||||
d: d,
|
||||
at: performance.now()
|
||||
});
|
||||
}
|
||||
|
||||
onServerAck = (id: number) => {
|
||||
this.messages = this.messages.filter(m => m.d.a !== id);
|
||||
}
|
||||
}
|
||||
|
||||
// versioned events, acks, retries, resync
|
||||
export default class StrongSocket {
|
||||
|
||||
|
@ -110,10 +79,10 @@ export default class StrongSocket {
|
|||
StrongSocket.resolveFirstConnect = r;
|
||||
});
|
||||
|
||||
constructor(readonly url: string, initialVersion: number | false, settings?: any) {
|
||||
constructor(readonly url: string, version: number | false, settings?: any) {
|
||||
this.settings = $.extend(true, {}, StrongSocket.defaults, settings);
|
||||
this.options = this.settings.options;
|
||||
this.version = initialVersion;
|
||||
this.version = version;
|
||||
this.pubsub.on('socket.send', this.send);
|
||||
window.addEventListener('unload', this.destroy);
|
||||
this.connect();
|
||||
|
@ -313,3 +282,33 @@ export default class StrongSocket {
|
|||
pingInterval = () => this.computePingDelay() + this.averageLag;
|
||||
getVersion = () => this.version;
|
||||
}
|
||||
|
||||
class Ackable {
|
||||
|
||||
currentId = 1; // increment with each ackable message sent
|
||||
messages: MsgAck[] = [];
|
||||
|
||||
constructor(readonly send: Send) {
|
||||
setInterval(this.resend, 1200);
|
||||
}
|
||||
|
||||
resend = () => {
|
||||
const resendCutoff = performance.now() - 2500;
|
||||
this.messages.forEach(m => {
|
||||
if (m.at < resendCutoff) this.send(m.t, m.d);
|
||||
});
|
||||
}
|
||||
|
||||
register = (t: Tpe, d: Payload) => {
|
||||
d.a = this.currentId++;
|
||||
this.messages.push({
|
||||
t: t,
|
||||
d: d,
|
||||
at: performance.now()
|
||||
});
|
||||
}
|
||||
|
||||
onServerAck = (id: number) => {
|
||||
this.messages = this.messages.filter(m => m.d.a !== id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ class SoundBox {
|
|||
|
||||
getVolume = () => {
|
||||
// garbage has been stored here by accident (e972d5612d)
|
||||
const v = parseFloat(this.volume.get());
|
||||
const v = parseFloat(this.volume.get() || '');
|
||||
return v >= 0 ? v : 0.7;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ window.lichess.load.then(() => {
|
|||
|
||||
if (!window.customWS) setTimeout(() => {
|
||||
if (!window.lichess.socket)
|
||||
window.lichess.socket = StrongSocket("/socket/v5", false);
|
||||
window.lichess.socket = new StrongSocket("/socket/v5", false);
|
||||
}, 300);
|
||||
|
||||
topBar();
|
||||
|
@ -146,12 +146,11 @@ window.lichess.load.then(() => {
|
|||
});
|
||||
|
||||
// still bind esc even in form fields
|
||||
window.Mousetrap.prototype.stopCallback = function(_, el, combo) {
|
||||
return combo != 'esc' && (
|
||||
window.Mousetrap.prototype.stopCallback = (_: any, el: HTMLElement, combo: string) =>
|
||||
combo != 'esc' && (
|
||||
el.isContentEditable || el.tagName == 'INPUT' || el.tagName == 'SELECT' || el.tagName == 'TEXTAREA'
|
||||
);
|
||||
};
|
||||
window.Mousetrap.bind('esc', function() {
|
||||
window.Mousetrap.bind('esc', () => {
|
||||
const $oc = $('#modal-wrap .close');
|
||||
if ($oc.length) $oc.trigger('click');
|
||||
else {
|
||||
|
@ -163,7 +162,7 @@ window.lichess.load.then(() => {
|
|||
|
||||
if (!storage.get('grid')) setTimeout(() => {
|
||||
if (getComputedStyle(document.body).getPropertyValue('--grid'))
|
||||
storage.set('grid', 1);
|
||||
storage.set('grid', '1');
|
||||
else
|
||||
$.get(assetUrl('oops/browser.html'), html => $('body').prepend(html))
|
||||
}, 3000);
|
||||
|
|
|
@ -8,11 +8,10 @@
|
|||
"noImplicitReturns": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedParameters": true,
|
||||
"noEmitOnError": false,
|
||||
"moduleResolution": "node",
|
||||
"target": "ES2016",
|
||||
"module": "commonjs",
|
||||
"lib": ["DOM", "ES2016"],
|
||||
"lib": ["DOM", "ES2016", "DOM.iterable"],
|
||||
"types": ["lichess", "jquery", "defer-promise"]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue