lila/ui/lobby/src/boot.ts

171 lines
5.7 KiB
TypeScript

import * as xhr from 'common/xhr';
import main from './main';
import modal from 'common/modal';
import { LobbyOpts } from './interfaces';
import { numberFormat } from 'common/number';
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' },
{ id: '3+2', lim: 3, inc: 2, perf: 'Blitz' },
{ id: '5+0', lim: 5, inc: 0, perf: 'Blitz' },
{ id: '5+3', lim: 5, inc: 3, perf: 'Blitz' },
{ id: '10+0', lim: 10, inc: 0, perf: 'Rapid' },
{ id: '10+5', lim: 10, inc: 5, perf: 'Rapid' },
{ id: '15+10', lim: 15, inc: 10, perf: 'Rapid' },
{ id: '30+0', lim: 30, inc: 0, perf: 'Classical' },
{ id: '30+20', lim: 30, inc: 20, perf: 'Classical' },
];
const nbRoundSpread = spreadNumber('#nb_games_in_play > strong', 8),
nbUserSpread = spreadNumber('#nb_connected_players > strong', 10),
getParameterByName = (name: string) => {
const match = RegExp('[?&]' + name + '=([^&]*)').exec(location.search);
return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
};
lichess.socket = new lichess.StrongSocket('/lobby/socket/v5', false, {
receive(t: string, d: any) {
lobby.socketReceive(t, d);
},
events: {
n(_: string, msg: any) {
nbUserSpread(msg.d);
setTimeout(() => nbRoundSpread(msg.r), lichess.socket.pingInterval() / 2);
},
reload_timeline() {
xhr.text('/timeline').then(html => {
$('.timeline').html(html);
lichess.contentLoaded();
});
},
featured(o: { html: string }) {
$('.lobby__tv').html(o.html);
lichess.contentLoaded();
},
redirect(e: RedirectTo) {
lobby.leavePool();
lobby.setRedirecting();
lichess.redirect(e);
},
fen(e: any) {
lobby.gameActivity(e.id);
},
},
});
lichess.StrongSocket.firstConnect.then(() => {
const gameId = getParameterByName('hook_like');
if (!gameId) return;
const ratingRange = lobby.setup.stores.hook.get()?.ratingRange;
xhr.text(`/setup/hook/${lichess.sri}/like/${gameId}?rr=${ratingRange || ''}`, { method: 'post' });
lobby.setTab('real_time');
history.replaceState(null, '', '/');
});
opts.blindMode = $('body').hasClass('blind-mode');
opts.trans = lichess.trans(opts.i18n);
opts.socketSend = lichess.socket.send;
const lobby = main(opts);
const $startButtons = $('.lobby__start'),
clickEvent = opts.blindMode ? 'click' : 'mousedown';
$startButtons
.find('a:not(.disabled)')
.on(clickEvent, function (this: HTMLAnchorElement) {
$(this).addClass('active').siblings().removeClass('active');
lichess.loadCssPath('lobby.setup');
lobby.leavePool();
let url = this.href;
if (this.dataset.hrefAddon) {
url += this.dataset.hrefAddon;
delete this.dataset.hrefAddon;
}
fetch(url, {
...xhr.defaultInit,
headers: xhr.xhrHeader,
}).then(res =>
res.text().then(text => {
if (res.ok) {
lobby.setup.prepareForm(
modal({
content: $(text),
class: 'game-setup',
onClose() {
$startButtons.find('.active').removeClass('active');
},
})
);
lichess.contentLoaded();
} else {
if (text && !text.startsWith('<!DOCTYPE html>')) alert(text);
lichess.reload();
}
})
);
})
.on('click', e => e.preventDefault());
if (['#ai', '#friend', '#hook'].includes(location.hash)) {
$startButtons
.find('.config_' + location.hash.replace('#', ''))
.each(function (this: HTMLElement) {
this.dataset.hrefAddon = location.search;
})
.trigger(clickEvent);
if (location.hash === '#hook') {
if (/time=realTime/.test(location.search)) lobby.setTab('real_time');
else if (/time=correspondence/.test(location.search)) lobby.setTab('seeks');
}
history.replaceState(null, '', '/');
}
suggestBgSwitch();
}
function suggestBgSwitch() {
const m = window.matchMedia('(prefers-color-scheme: dark)');
if (m.media == 'not all') return;
const current = document.body.getAttribute('data-theme');
if (m.matches == (current == 'dark')) return;
let dasher: Promise<any>;
const getDasher = (): Promise<any> => {
dasher =
dasher ||
lichess.loadModule('dasher').then(() => window.LichessDasher(document.createElement('div'), { playing: false }));
return dasher;
};
$('.bg-switch')
.addClass('active')
.on('click', () =>
getDasher().then(dasher =>
dasher.subs.background.set(document.body.classList.contains('dark') ? 'light' : 'dark')
)
);
}
function spreadNumber(selector: string, nbSteps: number) {
const el = document.querySelector(selector) as HTMLElement;
let previous = parseInt(el.getAttribute('data-count')!);
const display = (prev: number, cur: number, it: number) => {
el.textContent = numberFormat(Math.round((prev * (nbSteps - 1 - it) + cur * (it + 1)) / nbSteps));
};
let timeouts: number[] = [];
return (nb: number, overrideNbSteps?: number) => {
if (!el || (!nb && nb !== 0)) return;
if (overrideNbSteps) nbSteps = Math.abs(overrideNbSteps);
timeouts.forEach(clearTimeout);
timeouts = [];
const interv = Math.abs(lichess.socket.pingInterval() / nbSteps);
const prev = previous || nb;
previous = nb;
for (let i = 0; i < nbSteps; i++) timeouts.push(setTimeout(() => display(prev, nb, i), Math.round(i * interv)));
};
}