lila/ui/site/src/site.ts

194 lines
6.7 KiB
TypeScript

import * as miniBoard from 'common/mini-board';
import * as miniGame from './component/mini-game';
import * as timeago from './component/timeago';
import * as xhr from 'common/xhr';
import announce from './component/announce';
import exportLichessGlobals from './site.lichess.globals';
import info from './component/info';
import loadClockWidget from './component/clock-widget';
import moduleLaunchers from './component/module-launchers';
import OnlineFriends from './component/friends';
import powertip from './component/powertip';
import pubsub from './component/pubsub';
import serviceWorker from './component/serviceWorker';
import StrongSocket from './component/socket';
import topBar from './component/top-bar';
import watchers from './component/watchers';
import { reload } from './component/reload';
import { requestIdleCallback } from './component/functions';
import { userComplete } from './component/assets';
import { trapFocus } from 'common/modal';
exportLichessGlobals();
lichess.info = info;
loadClockWidget();
lichess.load.then(() => {
moduleLaunchers();
requestAnimationFrame(() => {
miniBoard.initAll();
miniGame.initAll();
pubsub.on('content-loaded', miniBoard.initAll);
pubsub.on('content-loaded', miniGame.initAll);
timeago.updateRegularly(1000);
pubsub.on('content-loaded', timeago.findAndRender);
});
requestIdleCallback(() => {
const friendsEl = document.getElementById('friend_box');
if (friendsEl) new OnlineFriends(friendsEl);
const chatMembers = document.querySelector('.chat__members') as HTMLElement | null;
if (chatMembers) watchers(chatMembers);
$('#main-wrap')
.on('click', '.autoselect', function (this: HTMLInputElement) {
this.select();
})
.on('click', 'button.copy', function (this: HTMLElement) {
$('#' + $(this).data('rel')).each(function (this: HTMLInputElement) {
this.select();
});
document.execCommand('copy');
$(this).attr('data-icon', '');
});
$('body').on('click', 'a.relation-button', function (this: HTMLAnchorElement) {
const $a = $(this).addClass('processing').css('opacity', 0.3);
xhr.text(this.href, { method: 'post' }).then(html => {
if (html.includes('relation-actions')) $a.parent().replaceWith(html);
else $a.replaceWith(html);
});
return false;
});
$('.mselect .button').on('click', function (this: HTMLElement) {
const $p = $(this).parent();
$p.toggleClass('shown');
requestIdleCallback(() => {
const handler = (e: Event) => {
if ($p[0]!.contains(e.target as HTMLElement)) return;
$p.removeClass('shown');
$('html').off('click', handler);
};
$('html').on('click', handler);
}, 200);
});
powertip.watchMouse();
setTimeout(() => {
if (!lichess.socket) lichess.socket = new StrongSocket('/socket/v5', false);
}, 300);
topBar();
window.addEventListener('resize', () => document.body.dispatchEvent(new Event('chessground.resize')));
$('.user-autocomplete').each(function (this: HTMLInputElement) {
const focus = !!this.autofocus;
const start = () =>
userComplete().then(uac =>
uac({
input: this,
friend: $(this).data('friend'),
tag: $(this).data('tag'),
focus,
})
);
if (focus) start();
else $(this).one('focus', start);
});
if (window.InfiniteScroll) window.InfiniteScroll('.infinite-scroll');
$('input.confirm, button.confirm').on('click', function (this: HTMLElement) {
return confirm(this.title || 'Confirm this action?');
});
$('#main-wrap').on('click', 'a.bookmark', function (this: HTMLAnchorElement) {
const t = $(this).toggleClass('bookmarked');
xhr.text(this.href, { method: 'post' });
const count = (parseInt(t.text(), 10) || 0) + (t.hasClass('bookmarked') ? 1 : -1);
t.find('span').html('' + (count > 0 ? count : ''));
return false;
});
$('body').on('focusin', trapFocus);
window.Mousetrap.bind('esc', () => {
const $oc = $('#modal-wrap .close');
if ($oc.length) $oc.trigger('click');
else {
const $input = $(':focus');
if ($input.length) $input.trigger('blur');
}
});
/* A disgusting hack for a disgusting browser
* Edge randomly fails to rasterize SVG on page load
* A different SVG must be loaded so a new image can be rasterized */
if (navigator.userAgent.includes('Edge/'))
setTimeout(() => {
const sprite = document.getElementById('piece-sprite') as HTMLLinkElement;
sprite.href = sprite.href.replace('.css', '.external.css');
}, 1000);
// prevent zoom when keyboard shows on iOS
if (/iPad|iPhone|iPod/.test(navigator.userAgent) && 'MSStream' in window) {
const el = document.querySelector('meta[name=viewport]') as HTMLElement;
el.setAttribute('content', el.getAttribute('content') + ',maximum-scale=1.0');
}
if (location.hash === '#blind' && !$('body').hasClass('blind-mode'))
xhr
.text('/toggle-blind-mode', {
method: 'post',
body: xhr.form({
enable: 1,
redirect: '/',
}),
})
.then(reload);
const pageAnnounce = document.body.getAttribute('data-announce');
if (pageAnnounce) announce(JSON.parse(pageAnnounce));
serviceWorker();
// socket default receive handlers
pubsub.on('socket.in.redirect', (d: RedirectTo) => {
lichess.unload.expected = true;
lichess.redirect(d);
});
pubsub.on('socket.in.fen', e =>
document.querySelectorAll('.mini-game-' + e.id).forEach((el: HTMLElement) => miniGame.update(el, e))
);
pubsub.on('socket.in.finish', e =>
document.querySelectorAll('.mini-game-' + e.id).forEach((el: HTMLElement) => miniGame.finish(el, e.win))
);
pubsub.on('socket.in.announce', announce);
pubsub.on('socket.in.tournamentReminder', (data: { id: string; name: string }) => {
if ($('#announce').length || $('body').data('tournament-id') == data.id) return;
const url = '/tournament/' + data.id;
$('body')
.append(
'<div id="announce">' +
`<a data-icon="" class="text" href="${url}">${data.name}</a>` +
'<div class="actions">' +
`<a class="withdraw text" href="${url}/withdraw" data-icon="">Pause</a>` +
`<a class="text" href="${url}" data-icon="">Resume</a>` +
'</div></div>'
)
.find('#announce .withdraw')
.on('click', function (this: HTMLAnchorElement) {
xhr.text(this.href, { method: 'post' });
$('#announce').remove();
return false;
});
});
}, 800);
});