lichess-pgn-viewer
Version:
PGN viewer widget, designed to be embedded in content pages.
95 lines • 3.78 kB
JavaScript
import { h } from 'snabbdom';
import { Path } from '../path';
export const renderMoves = (ctrl) => h('div.lpv__side', h('div.lpv__moves', {
hook: {
insert: vnode => {
const el = vnode.elm;
if (!ctrl.path.empty())
autoScroll(ctrl, el);
el.addEventListener('mousedown', e => {
const path = e.target.getAttribute('p');
if (path)
ctrl.toPath(new Path(path));
}, { passive: true });
},
postpatch: (_, vnode) => {
if (ctrl.autoScrollRequested) {
autoScroll(ctrl, vnode.elm);
ctrl.autoScrollRequested = false;
}
},
},
}, [...ctrl.game.initial.comments.map(commentNode), ...makeMoveNodes(ctrl)]));
const emptyMove = () => h('move.empty', '...');
const indexNode = (turn) => h('index', `${turn}.`);
const commentNode = (comment) => h('comment', comment);
const parenOpen = () => h('paren.open', '(');
const parenClose = () => h('paren.close', ')');
const moveTurn = (move) => Math.floor((move.ply - 1) / 2) + 1;
const makeMoveNodes = (ctrl) => {
const moveDom = renderMove(ctrl);
const elms = [];
let node, variations = ctrl.game.moves.children.slice(1);
if (ctrl.game.initial.pos.turn == 'black' && ctrl.game.mainline[0])
elms.push(indexNode(ctrl.game.initial.pos.fullmoves), emptyMove());
while ((node = (node || ctrl.game.moves).children[0])) {
const move = node.data;
const oddMove = move.ply % 2 == 1;
if (oddMove)
elms.push(indexNode(moveTurn(move)));
elms.push(moveDom(move));
const addEmptyMove = oddMove && (variations.length || move.comments.length) && node.children.length;
if (addEmptyMove)
elms.push(emptyMove());
move.comments.forEach(comment => elms.push(commentNode(comment)));
variations.forEach(variation => elms.push(makeMainVariation(moveDom, variation)));
if (addEmptyMove)
elms.push(indexNode(moveTurn(move)), emptyMove());
variations = node.children.slice(1);
}
return elms;
};
const makeMainVariation = (moveDom, node) => h('variation', [...node.data.startingComments.map(commentNode), ...makeVariationMoves(moveDom, node)]);
const makeVariationMoves = (moveDom, node) => {
let elms = [];
let variations = [];
if (node.data.ply % 2 == 0)
elms.push(h('index', [moveTurn(node.data), '...']));
do {
const move = node.data;
if (move.ply % 2 == 1)
elms.push(h('index', [moveTurn(move), '.']));
elms.push(moveDom(move));
move.comments.forEach(comment => elms.push(commentNode(comment)));
variations.forEach(variation => {
elms = [...elms, parenOpen(), ...makeVariationMoves(moveDom, variation), parenClose()];
});
variations = node.children.slice(1);
node = node.children[0];
} while (node);
return elms;
};
const renderMove = (ctrl) => (move) => h('move', {
class: {
current: ctrl.path.equals(move.path),
ancestor: ctrl.path.contains(move.path),
good: move.nags.includes(1),
mistake: move.nags.includes(2),
brilliant: move.nags.includes(3),
blunder: move.nags.includes(4),
interesting: move.nags.includes(5),
inaccuracy: move.nags.includes(6),
},
attrs: {
p: move.path.path,
},
}, move.san);
const autoScroll = (ctrl, cont) => {
const target = cont.querySelector('.current');
if (!target) {
cont.scrollTop = ctrl.path.empty() ? 0 : 99999;
return;
}
cont.scrollTop = target.offsetTop - cont.offsetHeight / 2 + target.offsetHeight;
};
//# sourceMappingURL=side.js.map