new puzzle UI WIP
This commit is contained in:
parent
8eb737fae9
commit
1d838ff770
|
@ -2,11 +2,11 @@
|
|||
|
||||
@evenMoreJs = {
|
||||
@embedJs {
|
||||
LichessPuzzle({
|
||||
element: document.querySelector('#lichess .round'),
|
||||
lichess = lichess || {};
|
||||
lichess.puzzle = {
|
||||
data: @Html(toJson(data)),
|
||||
i18n: @jsI18n()
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -21,5 +21,5 @@ description = s"Tactic puzzle #${puzzle.id}: " + puzzle.color.fold(
|
|||
trans.findTheBestMoveForWhite,
|
||||
trans.findTheBestMoveForBlack
|
||||
).str() + s" Played by ${puzzle.attempts} players.").some) {
|
||||
<div class="round cg-512">@miniBoardContent</div>
|
||||
<div class="puzzle_app cg-512">@miniBoardContent</div>
|
||||
}
|
||||
|
|
|
@ -35,7 +35,8 @@ object JsonView {
|
|||
"vote" -> puzzle.vote.sum
|
||||
),
|
||||
"pref" -> Json.obj(
|
||||
"coords" -> pref.coords
|
||||
"coords" -> pref.coords,
|
||||
"rookCastle" -> pref.rookCastle
|
||||
),
|
||||
"chessground" -> Json.obj(
|
||||
"highlight" -> Json.obj(
|
||||
|
|
|
@ -355,6 +355,7 @@ lichess.notifyApp = (function() {
|
|||
else if (lichess.user_analysis) startUserAnalysis(document.getElementById('lichess'), lichess.user_analysis);
|
||||
else if (lichess.study) startStudy(document.getElementById('lichess'), lichess.study);
|
||||
else if (lichess.lobby) startLobby(document.getElementById('hooks_wrap'), lichess.lobby);
|
||||
else if (lichess.puzzle) startPuzzle(lichess.puzzle);
|
||||
else if (lichess.tournament) startTournament(document.getElementById('tournament'), lichess.tournament);
|
||||
else if (lichess.simul) startSimul(document.getElementById('simul'), lichess.simul);
|
||||
|
||||
|
@ -1300,7 +1301,7 @@ lichess.notifyApp = (function() {
|
|||
window.history.replaceState(null, null, '/');
|
||||
};
|
||||
lichess.socket = lichess.StrongSocket(
|
||||
'/lobby/socket/v1',
|
||||
'/lobby/socket/v2',
|
||||
cfg.data.version, {
|
||||
receive: function(t, d) {
|
||||
lobby.socketReceive(t, d);
|
||||
|
@ -2002,6 +2003,30 @@ lichess.notifyApp = (function() {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////
|
||||
// puzzle.js //
|
||||
////////////////
|
||||
|
||||
function startPuzzle(cfg) {
|
||||
var puzzle;
|
||||
cfg.element = document.querySelector('#lichess .puzzle_app');
|
||||
cfg.sideElement = document.querySelector('#site_header .side_box');
|
||||
lichess.socket = lichess.StrongSocket('/socket', 0, {
|
||||
options: {
|
||||
name: "puzzle"
|
||||
},
|
||||
params: {
|
||||
ran: "--ranph--"
|
||||
},
|
||||
receive: function(t, d) {
|
||||
puzzle.socketReceive(t, d);
|
||||
}
|
||||
});
|
||||
cfg.socketSend = lichess.socket.send;
|
||||
puzzle = LichessPuzzle(cfg);
|
||||
topMenuIntent();
|
||||
}
|
||||
|
||||
/////////////// forum.js ////////////////////
|
||||
|
||||
$('#lichess_forum').on('click', 'a.delete', function() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var util = require('../util');
|
||||
var readDrops = require('chess').readDrops;
|
||||
|
||||
module.exports = {
|
||||
|
||||
|
@ -8,7 +8,7 @@ module.exports = {
|
|||
|
||||
if (piece.role === 'pawn' && (pos[1] === '1' || pos[1] === '8')) return false;
|
||||
|
||||
var drops = util.readDrops(possibleDrops);
|
||||
var drops = readDrops(possibleDrops);
|
||||
|
||||
if (drops === null) return true;
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ var actionMenu = require('./actionMenu').controller;
|
|||
var autoplay = require('./autoplay');
|
||||
var promotion = require('./promotion');
|
||||
var util = require('./util');
|
||||
var readDests = require('chess').readDests;
|
||||
var readDrops = require('chess').readDrops;
|
||||
var storedProp = require('common').storedProp;
|
||||
var throttle = require('common').throttle;
|
||||
var socket = require('./socket');
|
||||
|
@ -115,8 +117,8 @@ module.exports = function(opts) {
|
|||
var showGround = function() {
|
||||
var node = this.vm.node;
|
||||
var color = node.ply % 2 === 0 ? 'white' : 'black';
|
||||
var dests = util.readDests(node.dests);
|
||||
var drops = util.readDrops(node.drops);
|
||||
var dests = readDests(node.dests);
|
||||
var drops = readDrops(node.drops);
|
||||
var config = {
|
||||
fen: node.fen,
|
||||
turnColor: color,
|
||||
|
@ -147,8 +149,7 @@ module.exports = function(opts) {
|
|||
}.bind(this);
|
||||
|
||||
var getDests = throttle(800, false, function() {
|
||||
if (this.vm.node.dests) return;
|
||||
this.socket.sendAnaDests({
|
||||
if (!this.vm.node.dests) this.socket.sendAnaDests({
|
||||
variant: this.data.game.variant.key,
|
||||
fen: this.vm.node.fen,
|
||||
path: this.vm.path
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
var util = require('./util');
|
||||
var synthetic = require('./util').synthetic;
|
||||
var initialBoardFen = require('chessground').fen.initial;
|
||||
|
||||
module.exports = function(send, ctrl) {
|
||||
|
@ -18,7 +18,7 @@ module.exports = function(send, ctrl) {
|
|||
}
|
||||
} : {};
|
||||
|
||||
if (!util.synthetic(ctrl.data)) setTimeout(function() {
|
||||
if (!synthetic(ctrl.data)) setTimeout(function() {
|
||||
send("startWatching", ctrl.data.game.id);
|
||||
}, 1000);
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
var piotr2key = require('./piotr');
|
||||
var fixCrazySan = require('chess').fixCrazySan;
|
||||
var common = require('common');
|
||||
var m = require('mithril');
|
||||
|
@ -8,20 +7,6 @@ var plyToTurn = function(ply) {
|
|||
}
|
||||
|
||||
module.exports = {
|
||||
readDests: function(lines) {
|
||||
if (!common.defined(lines)) return null;
|
||||
var dests = {};
|
||||
if (lines) lines.split(' ').forEach(function(line) {
|
||||
dests[piotr2key[line[0]]] = line.split('').slice(1).map(function(c) {
|
||||
return piotr2key[c];
|
||||
});
|
||||
});
|
||||
return dests;
|
||||
},
|
||||
readDrops: function(line) {
|
||||
if (!common.defined(line) || line === null) return null;
|
||||
return line.match(/.{2}/g) || [];
|
||||
},
|
||||
synthetic: function(data) {
|
||||
return data.game.id === 'synthetic';
|
||||
},
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
var piotr = require('./piotr');
|
||||
|
||||
module.exports = {
|
||||
|
||||
initialFen: 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1',
|
||||
|
@ -12,5 +14,20 @@ module.exports = {
|
|||
renderEval: function(e) {
|
||||
e = Math.max(Math.min(Math.round(e / 10) / 10, 99), -99);
|
||||
return (e > 0 ? '+' : '') + e;
|
||||
},
|
||||
|
||||
readDests: function(lines) {
|
||||
if (typeof lines === 'undefined') return null;
|
||||
var dests = {};
|
||||
if (lines) lines.split(' ').forEach(function(line) {
|
||||
dests[piotr[line[0]]] = line.split('').slice(1).map(function(c) {
|
||||
return piotr[c];
|
||||
});
|
||||
});
|
||||
return dests;
|
||||
},
|
||||
readDrops: function(line) {
|
||||
if (typeof line === 'undefined' || line === null) return null;
|
||||
return line.match(/.{2}/g) || [];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,35 +1,152 @@
|
|||
var m = require('mithril');
|
||||
var makeTree = require('tree').tree;
|
||||
var treeBuild = require('tree').build;
|
||||
var treeOps = require('tree').ops;
|
||||
var cevalCtrl = require('ceval').ctrl;
|
||||
var readDests = require('chess').readDests;
|
||||
var k = Mousetrap;
|
||||
var chessground = require('chessground');
|
||||
var partial = chessground.util.partial;
|
||||
var opposite = chessground.util.opposite;
|
||||
var groundBuild = require('./ground');
|
||||
var socketBuild = require('./socket');
|
||||
var throttle = require('common').throttle;
|
||||
var xhr = require('./xhr');
|
||||
var sound = require('./sound');
|
||||
|
||||
module.exports = function(data, i18n) {
|
||||
module.exports = function(opts, i18n) {
|
||||
|
||||
var vm = {
|
||||
loading: false
|
||||
loading: false,
|
||||
justPlayed: null,
|
||||
};
|
||||
|
||||
var tree = makeTree(treeOps.reconstruct(data.game.treeParts));
|
||||
var data = opts.data;
|
||||
var tree = treeBuild(treeOps.reconstruct(opts.data.game.treeParts));
|
||||
var ground;
|
||||
|
||||
var setPath = function(path) {
|
||||
vm.path = path;
|
||||
vm.nodeList = tree.getNodeList(path);
|
||||
vm.node = treeOps.last(vm.nodeList);
|
||||
vm.mainline = treeOps.mainlineNodeList(tree.root);
|
||||
}.bind(this);
|
||||
};
|
||||
|
||||
setPath('');
|
||||
|
||||
setPath(initialPath);
|
||||
var showGround = function() {
|
||||
var node = vm.node;
|
||||
var color = node.ply % 2 === 0 ? 'white' : 'black';
|
||||
var dests = readDests(node.dests);
|
||||
var config = {
|
||||
fen: node.fen,
|
||||
turnColor: color,
|
||||
movable: {
|
||||
color: (dests && Object.keys(dests).length > 0) ? color : null,
|
||||
dests: dests || {}
|
||||
},
|
||||
check: node.check,
|
||||
lastMove: uciToLastMove(node.uci)
|
||||
};
|
||||
if (!dests && !node.check) {
|
||||
// premove while dests are loading from server
|
||||
// can't use when in check because it highlights the wrong king
|
||||
config.turnColor = opposite(color);
|
||||
config.movable.color = color;
|
||||
}
|
||||
vm.cgConfig = config;
|
||||
if (!ground) ground = groundBuild(data, config, userMove);
|
||||
ground.set(config);
|
||||
if (!dests) getDests();
|
||||
};
|
||||
|
||||
var userMove = function(orig, dest, capture) {
|
||||
vm.justPlayed = orig;
|
||||
sound[capture ? 'capture' : 'move']();
|
||||
sendMove(orig, dest);
|
||||
};
|
||||
|
||||
var getDests = throttle(800, false, function() {
|
||||
if (!vm.node.dests) socket.sendAnaDests({
|
||||
fen: vm.node.fen,
|
||||
path: vm.path
|
||||
});
|
||||
});
|
||||
|
||||
var uciToLastMove = function(uci) {
|
||||
if (!uci) return;
|
||||
return [uci.substr(0, 2), uci.substr(2, 2)]; // assuming standard chess
|
||||
};
|
||||
|
||||
var addNode = function(node, path) {
|
||||
var newPath = tree.addNode(node, path);
|
||||
jump(newPath);
|
||||
m.redraw();
|
||||
ground.playPremove();
|
||||
};
|
||||
|
||||
var addDests = function(dests, path, opening) {
|
||||
tree.addDests(dests, path, opening);
|
||||
if (path === vm.path) {
|
||||
showGround();
|
||||
m.redraw();
|
||||
if (gameOver()) ceval.stop();
|
||||
}
|
||||
ground.playPremove();
|
||||
};
|
||||
|
||||
var gameOver = function() {
|
||||
if (vm.node.dests !== '') return false;
|
||||
if (vm.node.check) {
|
||||
var san = vm.node.san;
|
||||
var checkmate = san && san[san.length - 1] === '#';
|
||||
return checkmate;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var jump = function(path) {
|
||||
var pathChanged = path !== vm.path;
|
||||
setPath(path);
|
||||
showGround();
|
||||
if (pathChanged) {
|
||||
if (!vm.node.uci) sound.move(); // initial position
|
||||
else if (vm.node.uci.indexOf(vm.justPlayed) !== 0) {
|
||||
if (vm.node.san.indexOf('x') !== -1) sound.capture();
|
||||
else sound.move();
|
||||
}
|
||||
if (/\+|\#/.test(vm.node.san)) sound.check();
|
||||
// this.vm.threatMode = false;
|
||||
// this.ceval.stop();
|
||||
// this.startCeval();
|
||||
}
|
||||
vm.justPlayed = null;
|
||||
vm.autoScrollRequested = true;
|
||||
};
|
||||
|
||||
var userJump = function(path) {
|
||||
ground.selectSquare(null);
|
||||
jump(path);
|
||||
};
|
||||
|
||||
var socket = socketBuild({
|
||||
send: opts.socketSend,
|
||||
addNode: addNode,
|
||||
addDests: addDests,
|
||||
reset: function() {
|
||||
showGround();
|
||||
m.redraw();
|
||||
}
|
||||
});
|
||||
|
||||
showGround();
|
||||
|
||||
console.log(data);
|
||||
|
||||
return {
|
||||
vm: vm,
|
||||
trans: lichess.trans(i18n)
|
||||
tree: tree,
|
||||
ground: ground,
|
||||
userJump: userJump,
|
||||
trans: lichess.trans(opts.i18n),
|
||||
socketReceive: socket.receive
|
||||
};
|
||||
}
|
||||
|
|
40
ui/puzzle/src/ground.js
Normal file
40
ui/puzzle/src/ground.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
var chessground = require('chessground');
|
||||
|
||||
function makeConfig(data, config, onMove) {
|
||||
return {
|
||||
fen: config.fen,
|
||||
check: config.check,
|
||||
lastMove: config.lastMove,
|
||||
orientation: data.orientation,
|
||||
coordinates: data.pref.coords !== 0,
|
||||
movable: {
|
||||
free: false,
|
||||
color: config.movable.color,
|
||||
dests: config.movable.dests,
|
||||
rookCastle: data.pref.rookCastle
|
||||
},
|
||||
events: {
|
||||
move: onMove
|
||||
},
|
||||
premovable: {
|
||||
enabled: config.movable.enabled
|
||||
},
|
||||
drawable: {
|
||||
enabled: true
|
||||
},
|
||||
highlight: {
|
||||
lastMove: true,
|
||||
check: true,
|
||||
dragOver: true
|
||||
},
|
||||
animation: {
|
||||
enabled: true,
|
||||
duration: data.pref.animationDuration
|
||||
},
|
||||
disableContextMenu: true
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = function(data, config, onMove) {
|
||||
return new chessground.controller(makeConfig(data, config, onMove));
|
||||
};
|
|
@ -4,7 +4,7 @@ var m = require('mithril');
|
|||
|
||||
module.exports = function(opts) {
|
||||
|
||||
var controller = new ctrl(opts.data, opts.i18n);
|
||||
var controller = new ctrl(opts);
|
||||
|
||||
m.module(opts.element, {
|
||||
controller: function() {
|
||||
|
|
59
ui/puzzle/src/socket.js
Normal file
59
ui/puzzle/src/socket.js
Normal file
|
@ -0,0 +1,59 @@
|
|||
module.exports = function(opts) {
|
||||
|
||||
var anaMoveTimeout;
|
||||
var anaDestsTimeout;
|
||||
|
||||
var anaDestsCache = {};
|
||||
|
||||
var handlers = {
|
||||
stepFailure: function(data) {
|
||||
clearTimeout(anaMoveTimeout);
|
||||
opts.reset();
|
||||
},
|
||||
dests: function(data) {
|
||||
anaDestsCache[data.path] = data;
|
||||
opts.addDests(data.dests, data.path, data.opening);
|
||||
clearTimeout(anaDestsTimeout);
|
||||
},
|
||||
destsFailure: function(data) {
|
||||
console.log(data);
|
||||
clearTimeout(anaDestsTimeout);
|
||||
}
|
||||
};
|
||||
|
||||
var sendAnaMove = function(req) {
|
||||
clearTimeout(anaMoveTimeout);
|
||||
opts.send('anaMove', req);
|
||||
anaMoveTimeout = setTimeout(function() {
|
||||
sendAnaMove(req);
|
||||
}, 3000);
|
||||
};
|
||||
|
||||
var sendAnaDests = function(req) {
|
||||
clearTimeout(anaDestsTimeout);
|
||||
if (anaDestsCache[req.path]) setTimeout(function() {
|
||||
handlers.dests(anaDestsCache[req.path]);
|
||||
}, 300);
|
||||
else {
|
||||
opts.send('anaDests', req);
|
||||
anaDestsTimeout = setTimeout(function() {
|
||||
sendAnaDests(req);
|
||||
}, 3000);
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
send: opts.send,
|
||||
receive: function(type, data) {
|
||||
if (handlers[type]) {
|
||||
handlers[type](data);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
sendAnaMove: sendAnaMove,
|
||||
|
||||
sendAnaDests: sendAnaDests
|
||||
};
|
||||
}
|
11
ui/puzzle/src/sound.js
Normal file
11
ui/puzzle/src/sound.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
var throttle = require('common').throttle;
|
||||
|
||||
module.exports = $.sound ? {
|
||||
move: throttle(50, false, $.sound.move),
|
||||
capture: throttle(50, false, $.sound.capture),
|
||||
check: throttle(50, false, $.sound.check)
|
||||
} : {
|
||||
move: $.noop,
|
||||
capture: $.noop,
|
||||
check: $.noop
|
||||
};
|
|
@ -1,13 +1,9 @@
|
|||
var m = require('mithril');
|
||||
var raf = require('chessground').util.requestAnimationFrame;
|
||||
var throttle = require('common').throttle;
|
||||
var empty = require('common').empty;
|
||||
var defined = require('common').defined;
|
||||
var game = require('game').game;
|
||||
var fixCrazySan = require('chess').fixCrazySan;
|
||||
var normalizeEval = require('chess').renderEval;
|
||||
var treePath = require('tree').path;
|
||||
var commentAuthorText = require('./study/studyComments').authorText;
|
||||
|
||||
var autoScroll = throttle(300, false, function(ctrl, el) {
|
||||
var cont = el.parentNode;
|
||||
|
@ -46,48 +42,36 @@ function renderChildrenOf(ctx, node, opts) {
|
|||
var cs = node.children;
|
||||
var main = cs[0];
|
||||
if (!main) return;
|
||||
var conceal = opts.noConceal ? null : (opts.conceal || ctx.concealOf(true)(opts.parentPath + main.id, main));
|
||||
if (conceal === 'hide') return;
|
||||
if (opts.isMainline) {
|
||||
var isWhite = main.ply % 2 === 1;
|
||||
var commentTags = renderMainlineCommentsOf(ctx, main, {
|
||||
conceal: conceal,
|
||||
withColor: true
|
||||
}).filter(nonEmpty);
|
||||
if (!cs[1] && empty(commentTags)) return [
|
||||
if (!cs[1]) return [
|
||||
isWhite ? renderIndex(main.ply, false) : null,
|
||||
renderMoveAndChildrenOf(ctx, main, {
|
||||
parentPath: opts.parentPath,
|
||||
isMainline: true,
|
||||
conceal: conceal
|
||||
isMainline: true
|
||||
})
|
||||
];
|
||||
var mainChildren = renderChildrenOf(ctx, main, {
|
||||
parentPath: opts.parentPath + main.id,
|
||||
isMainline: true,
|
||||
conceal: conceal
|
||||
isMainline: true
|
||||
});
|
||||
var passOpts = {
|
||||
parentPath: opts.parentPath,
|
||||
isMainline: true,
|
||||
conceal: conceal
|
||||
isMainline: true
|
||||
};
|
||||
return [
|
||||
isWhite ? renderIndex(main.ply, false) : null,
|
||||
renderMoveOf(ctx, main, passOpts),
|
||||
isWhite ? emptyMove(passOpts) : null,
|
||||
isWhite ? emptyMove() : null,
|
||||
m('interrupt', [
|
||||
commentTags,
|
||||
renderLines(ctx, cs.slice(1), {
|
||||
parentPath: opts.parentPath,
|
||||
isMainline: true,
|
||||
conceal: conceal,
|
||||
noConceal: !conceal
|
||||
isMainline: true
|
||||
})
|
||||
]),
|
||||
isWhite && mainChildren ? [
|
||||
renderIndex(main.ply, false),
|
||||
emptyMove(passOpts)
|
||||
emptyMove()
|
||||
] : null,
|
||||
mainChildren
|
||||
];
|
||||
|
@ -100,15 +84,13 @@ function renderLines(ctx, nodes, opts) {
|
|||
return {
|
||||
tag: 'lines',
|
||||
attrs: {
|
||||
class: (nodes[1] ? '' : 'single') // + (opts.conceal ? ' ' + opts.conceal : '')
|
||||
class: nodes[1] ? '' : 'single'
|
||||
},
|
||||
children: nodes.map(function(n) {
|
||||
return lineTag(renderMoveAndChildrenOf(ctx, n, {
|
||||
parentPath: opts.parentPath,
|
||||
isMainline: false,
|
||||
withIndex: true,
|
||||
noConceal: opts.noConceal,
|
||||
truncate: n.comp && !pathContains(ctx, opts.parentPath + n.id) ? 3 : null
|
||||
withIndex: true
|
||||
}));
|
||||
})
|
||||
};
|
||||
|
@ -130,20 +112,14 @@ function renderMainlineMoveOf(ctx, node, opts) {
|
|||
var attrs = {
|
||||
p: path
|
||||
};
|
||||
var classes = [];
|
||||
if (path === ctx.ctrl.vm.path) classes.push('active');
|
||||
if (path === ctx.ctrl.vm.contextMenuPath) classes.push('context_menu');
|
||||
if (path === ctx.ctrl.vm.initialPath && game.playable(ctx.ctrl.data)) classes.push('current');
|
||||
if (opts.conceal) classes.push(opts.conceal);
|
||||
if (classes.length) attrs.class = classes.join(' ');
|
||||
if (path === ctx.ctrl.vm.path) attrs.class = 'active';
|
||||
return moveTag(attrs, renderMove(ctx, node));
|
||||
}
|
||||
|
||||
function renderMove(ctx, node) {
|
||||
var eval = node.eval || node.ceval || {};
|
||||
return [
|
||||
fixCrazySan(node.san),
|
||||
(node.glyphs && ctx.showGlyphs) ? renderGlyphs(node.glyphs) : null,
|
||||
node.san,
|
||||
defined(eval.cp) ? renderEval(normalizeEval(eval.cp)) : (
|
||||
defined(eval.mate) ? renderEval('#' + eval.mate) : null
|
||||
),
|
||||
|
@ -159,29 +135,20 @@ function renderVariationMoveOf(ctx, node, opts) {
|
|||
var classes = [];
|
||||
if (path === ctx.ctrl.vm.path) classes.push('active');
|
||||
else if (pathContains(ctx, path)) classes.push('parent');
|
||||
if (path === ctx.ctrl.vm.contextMenuPath) classes.push('context_menu');
|
||||
if (opts.conceal) classes.push(ctx.conceal);
|
||||
if (classes.length) attrs.class = classes.join(' ');
|
||||
return moveTag(attrs, [
|
||||
withIndex ? renderIndex(node.ply, true) : null,
|
||||
fixCrazySan(node.san),
|
||||
node.glyphs ? renderGlyphs(node.glyphs) : null
|
||||
node.san
|
||||
]);
|
||||
}
|
||||
|
||||
function renderMoveAndChildrenOf(ctx, node, opts) {
|
||||
var path = opts.parentPath + node.id;
|
||||
if (opts.truncate === 0) return moveTag({
|
||||
p: path
|
||||
}, [m('index', '[...]')]);
|
||||
return [
|
||||
renderMoveOf(ctx, node, opts),
|
||||
renderVariationCommentsOf(ctx, node),
|
||||
renderChildrenOf(ctx, node, {
|
||||
parentPath: path,
|
||||
isMainline: opts.isMainline,
|
||||
noConceal: opts.noConceal,
|
||||
truncate: opts.truncate ? opts.truncate - 1 : null
|
||||
isMainline: opts.isMainline
|
||||
})
|
||||
];
|
||||
}
|
||||
|
@ -194,24 +161,12 @@ function moveTag(attrs, content) {
|
|||
};
|
||||
}
|
||||
|
||||
function emptyMove(opts) {
|
||||
function emptyMove() {
|
||||
return moveTag({
|
||||
class: 'empty' + (opts.conceal ? ' ' + opts.conceal : '')
|
||||
class: 'empty'
|
||||
}, '...');
|
||||
}
|
||||
|
||||
function renderGlyphs(glyphs) {
|
||||
return glyphs.map(function(glyph) {
|
||||
return {
|
||||
tag: 'glyph',
|
||||
attrs: {
|
||||
title: glyph.name
|
||||
},
|
||||
children: [glyph.symbol]
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function renderEval(e) {
|
||||
return {
|
||||
tag: 'eval',
|
||||
|
@ -219,80 +174,18 @@ function renderEval(e) {
|
|||
};
|
||||
}
|
||||
|
||||
function renderMainlineCommentsOf(ctx, node, opts) {
|
||||
if (!ctx.ctrl.vm.comments || empty(node.comments)) return [];
|
||||
var colorClass = opts.withColor ? (node.ply % 2 === 0 ? 'black ' : 'white ') : '';
|
||||
return node.comments.map(function(comment) {
|
||||
if (comment.by === 'lichess' && !ctx.showComputer) return;
|
||||
var klass = '';
|
||||
if (comment.text.indexOf('Inaccuracy.') === 0) klass = 'inaccuracy';
|
||||
else if (comment.text.indexOf('Mistake.') === 0) klass = 'mistake';
|
||||
else if (comment.text.indexOf('Blunder.') === 0) klass = 'blunder';
|
||||
if (opts.conceal) klass += ' ' + opts.conceal;
|
||||
return renderMainlineComment(comment, colorClass + klass, node.comments.length > 1, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
function renderMainlineComment(comment, klass, withAuthor, ctx) {
|
||||
return {
|
||||
tag: 'comment',
|
||||
attrs: {
|
||||
class: klass
|
||||
},
|
||||
children: [
|
||||
withAuthor ? m('span.by', commentAuthorText(comment.by)) : null,
|
||||
truncateComment(comment.text, 400, ctx)
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function renderVariationCommentsOf(ctx, node) {
|
||||
if (!ctx.ctrl.vm.comments || empty(node.comments)) return [];
|
||||
return node.comments.map(function(comment) {
|
||||
if (comment.by === 'lichess' && !ctx.showComputer) return;
|
||||
return renderVariationComment(comment, node.comments.length > 1, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
function renderVariationComment(comment, withAuthor, ctx) {
|
||||
return {
|
||||
tag: 'comment',
|
||||
children: [
|
||||
withAuthor ? m('span.by', commentAuthorText(comment.by)) : null,
|
||||
truncateComment(comment.text, 300, ctx)
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
function truncateComment(text, len, ctx) {
|
||||
if (ctx.ctrl.embed) return text;
|
||||
if (text.length <= len) return text;
|
||||
return text.slice(0, len - 10) + ' [...]';
|
||||
}
|
||||
|
||||
function eventPath(e, ctrl) {
|
||||
return e.target.getAttribute('p') || e.target.parentNode.getAttribute('p');
|
||||
}
|
||||
|
||||
var noop = function() {};
|
||||
|
||||
function emptyConcealOf() {
|
||||
return noop;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
render: function(ctrl, concealOf) {
|
||||
render: function(ctrl) {
|
||||
var root = ctrl.tree.root;
|
||||
var ctx = {
|
||||
ctrl: ctrl,
|
||||
concealOf: concealOf || emptyConcealOf,
|
||||
showComputer: ctrl.vm.showComputer(),
|
||||
showGlyphs: !!ctrl.study || ctrl.vm.showComputer()
|
||||
showComputer: false,
|
||||
showGlyphs: false
|
||||
};
|
||||
var commentTags = renderMainlineCommentsOf(ctx, root, {
|
||||
withColor: false,
|
||||
conceal: false
|
||||
});
|
||||
return m('div.tview2', {
|
||||
config: function(el, isUpdate) {
|
||||
if (ctrl.vm.autoScrollRequested || !isUpdate) {
|
||||
|
@ -300,15 +193,6 @@ module.exports = {
|
|||
ctrl.vm.autoScrollRequested = false;
|
||||
}
|
||||
if (isUpdate) return;
|
||||
el.oncontextmenu = function(e) {
|
||||
var path = eventPath(e, ctrl);
|
||||
contextMenu.open(e, {
|
||||
path: path,
|
||||
root: ctrl
|
||||
});
|
||||
m.redraw();
|
||||
return false;
|
||||
};
|
||||
el.addEventListener('mousedown', function(e) {
|
||||
if (defined(e.button) && e.button !== 0) return; // only touch or left click
|
||||
var path = eventPath(e, ctrl);
|
||||
|
@ -317,10 +201,9 @@ module.exports = {
|
|||
});
|
||||
},
|
||||
}, [
|
||||
empty(commentTags) ? null : m('interrupt', commentTags),
|
||||
root.ply % 2 === 1 ? [
|
||||
renderIndex(root.ply, false),
|
||||
emptyMove({})
|
||||
emptyMove()
|
||||
] : null,
|
||||
renderChildrenOf(ctx, root, {
|
||||
parentPath: '',
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
var m = require('mithril');
|
||||
var chessground = require('chessground');
|
||||
var treeView = require('./treeView');
|
||||
|
||||
function renderOpeningBox(ctrl) {
|
||||
var opening = ctrl.tree.getOpening(ctrl.vm.nodeList);
|
||||
|
@ -14,11 +16,35 @@ function renderOpeningBox(ctrl) {
|
|||
function renderAnalyse(ctrl) {
|
||||
return m('div.areplay', [
|
||||
renderOpeningBox(ctrl),
|
||||
treeView.render(ctrl, concealOf),
|
||||
treeView.render(ctrl),
|
||||
// renderResult(ctrl)
|
||||
]);
|
||||
}
|
||||
|
||||
function wheel(ctrl, e) {
|
||||
if (e.target.tagName !== 'PIECE' && e.target.tagName !== 'SQUARE' && !e.target.classList.contains('cg-board')) return;
|
||||
if (e.deltaY > 0) control.next(ctrl);
|
||||
else if (e.deltaY < 0) control.prev(ctrl);
|
||||
m.redraw();
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
|
||||
function visualBoard(ctrl) {
|
||||
return m('div.lichess_board_wrap', [
|
||||
m('div.lichess_board', {
|
||||
config: function(el, isUpdate) {
|
||||
if (!isUpdate) el.addEventListener('wheel', function(e) {
|
||||
return wheel(ctrl, e);
|
||||
});
|
||||
}
|
||||
}, [
|
||||
chessground.view(ctrl.ground)
|
||||
]),
|
||||
// cevalView.renderGauge(ctrl)
|
||||
]);
|
||||
}
|
||||
|
||||
var firstRender = true;
|
||||
|
||||
module.exports = function(ctrl) {
|
||||
|
@ -39,7 +65,7 @@ module.exports = function(ctrl) {
|
|||
m('div.lichess_ground', [
|
||||
// cevalView.renderCeval(ctrl),
|
||||
// cevalView.renderPvs(ctrl),
|
||||
renderAnalyse(ctrl, concealOf),
|
||||
renderAnalyse(ctrl),
|
||||
// buttons(ctrl)
|
||||
])
|
||||
])
|
||||
|
|
Loading…
Reference in a new issue