200 lines
6.2 KiB
JavaScript
200 lines
6.2 KiB
JavaScript
var chessground = require('chessground');
|
|
var partial = chessground.util.partial;
|
|
var editor = require('./editor');
|
|
var drag = require('./drag');
|
|
var m = require('mithril');
|
|
|
|
function castleCheckBox(ctrl, id, label, reversed) {
|
|
var input = m('input[type=checkbox]', {
|
|
checked: ctrl.data.castles[id](),
|
|
onchange: function(e) {
|
|
ctrl.setCastle(id, e.target.checked);
|
|
}
|
|
});
|
|
return m('label', reversed ? [input, label] : [label, input]);
|
|
}
|
|
|
|
function optgroup(name, opts) {
|
|
return m('optgroup', {
|
|
label: name
|
|
}, opts);
|
|
}
|
|
|
|
function controls(ctrl, fen) {
|
|
var positionIndex = ctrl.positionIndex[fen.split(' ')[0]];
|
|
var currentPosition = ctrl.data.positions && positionIndex !== -1 ? ctrl.data.positions[positionIndex] : null;
|
|
var encodedFen = fen.replace(/\s/g, '_');
|
|
var position2option = function(pos) {
|
|
return {
|
|
tag: 'option',
|
|
attrs: {
|
|
value: pos.fen,
|
|
selected: currentPosition && currentPosition.fen === pos.fen
|
|
},
|
|
children: [pos.eco ? pos.eco + " " + pos.name : pos.name]
|
|
};
|
|
}
|
|
return m('div.editor-side', [
|
|
ctrl.embed ? null : m('div', [
|
|
ctrl.data.positions ? m('select.positions', {
|
|
onchange: function(e) {
|
|
ctrl.loadNewFen(e.target.value);
|
|
}
|
|
}, [
|
|
optgroup('Set the board', [
|
|
currentPosition ? null : m('option', {
|
|
value: fen,
|
|
selected: true
|
|
}, '- Position -'),
|
|
ctrl.extraPositions.map(position2option)
|
|
]),
|
|
optgroup('Popular openings',
|
|
ctrl.data.positions.map(position2option)
|
|
)
|
|
]) : null
|
|
]),
|
|
m('div.metadata.content_box', [
|
|
m('div.color',
|
|
m('select', {
|
|
onchange: m.withAttr('value', ctrl.setColor)
|
|
}, ['whitePlays', 'blackPlays'].map(function(key) {
|
|
return m('option', {
|
|
value: key[0],
|
|
selected: ctrl.data.color() === key[0]
|
|
}, ctrl.trans(key));
|
|
}))
|
|
),
|
|
m('div.castling', [
|
|
m('strong', ctrl.trans('castling')),
|
|
m('div', [
|
|
castleCheckBox(ctrl, 'K', ctrl.trans('whiteCastlingKingside'), ctrl.options.inlineCastling),
|
|
castleCheckBox(ctrl, 'Q', ctrl.trans('whiteCastlingQueenside'), true)
|
|
]),
|
|
m('div', [
|
|
castleCheckBox(ctrl, 'k', ctrl.trans('blackCastlingKingside'), ctrl.options.inlineCastling),
|
|
castleCheckBox(ctrl, 'q', ctrl.trans('blackCastlingQueenside'), true)
|
|
])
|
|
])
|
|
]),
|
|
ctrl.embed ? m('div', [
|
|
m('a.button.frameless', {
|
|
onclick: ctrl.startPosition
|
|
}, 'Initial position'),
|
|
m('a.button.frameless', {
|
|
onclick: ctrl.clearBoard
|
|
}, 'Empty board')
|
|
]) : m('div', [
|
|
m('a.button.text[data-icon=B]', {
|
|
onclick: ctrl.chessground.toggleOrientation
|
|
}, ctrl.trans('flipBoard')),
|
|
ctrl.positionLooksLegit() ? m('a.button.text[data-icon="A"]', {
|
|
href: editor.makeUrl('/analysis/', fen),
|
|
rel: 'nofollow'
|
|
}, ctrl.trans('analysis')) : m('span.button.disabled.text[data-icon="A"]', {
|
|
rel: 'nofollow'
|
|
}, ctrl.trans('analysis')),
|
|
m('a.button', {
|
|
onclick: function() {
|
|
$.modal($('.continue_with'));
|
|
}
|
|
},
|
|
m('span.text[data-icon=U]', ctrl.trans('continueFromHere')))
|
|
]),
|
|
ctrl.embed ? null : m('div.continue_with', [
|
|
m('a.button', {
|
|
href: '/?fen=' + encodedFen + '#ai',
|
|
rel: 'nofollow'
|
|
}, ctrl.trans('playWithTheMachine')),
|
|
m('br'),
|
|
m('a.button', {
|
|
href: '/?fen=' + encodedFen + '#friend',
|
|
rel: 'nofollow'
|
|
}, ctrl.trans('playWithAFriend'))
|
|
])
|
|
]);
|
|
}
|
|
|
|
function inputs(ctrl, fen) {
|
|
if (ctrl.embed) return;
|
|
if (ctrl.vm.redirecting) return m.trust(lichess.spinnerHtml);
|
|
return m('div.copyables', [
|
|
m('p', [
|
|
m('strong.name', 'FEN'),
|
|
m('input.copyable.autoselect[spellCheck=false]', {
|
|
value: fen,
|
|
onchange: function(e) {
|
|
if (e.target.value !== fen) ctrl.changeFen(e.target.value);
|
|
}
|
|
})
|
|
]),
|
|
m('p', [
|
|
m('strong.name', 'URL'),
|
|
m('input.copyable.autoselect[readonly][spellCheck=false]', {
|
|
value: editor.makeUrl(ctrl.data.baseUrl, fen)
|
|
})
|
|
])
|
|
]);
|
|
}
|
|
|
|
function sparePieces(ctrl, color, orientation, position) {
|
|
return m('div', {
|
|
class: ['spare', position, 'orientation-' + orientation, color].join(' ')
|
|
}, ['pointer', 'king', 'queen', 'rook', 'bishop', 'knight', 'pawn', 'trash'].map(function(role) {
|
|
var piece = ((['pointer', 'trash'].indexOf(role) === -1) ? color + ' ' : '') + role,
|
|
selectedParts = ctrl.vm.selected().split(' '),
|
|
cursorName = selectedParts[0] + ((selectedParts.length >= 2) ? '-' + selectedParts[1] : ''),
|
|
cursor = (cursorName === 'pointer') ?
|
|
// http://www.cursors-4u.com
|
|
cursorName : 'url(/assets/cursors/' + cursorName + '.cur), default !important',
|
|
pieceElement = {
|
|
class: piece,
|
|
style: 'cursor: ' + cursor
|
|
},
|
|
containerClass = 'no-square' + ((ctrl.vm.selected() === piece) ? ' selected-square' : '');
|
|
|
|
if (piece === 'trash') {
|
|
pieceElement['data-icon'] = 'q';
|
|
containerClass += ' trash';
|
|
} else {
|
|
pieceElement['data-color'] = color;
|
|
pieceElement['data-role'] = role;
|
|
}
|
|
|
|
return m('div', {
|
|
class: containerClass,
|
|
onmousedown: function() {
|
|
ctrl.vm.selected(piece);
|
|
}
|
|
}, m('piece', pieceElement)
|
|
);
|
|
}));
|
|
}
|
|
|
|
var eventNames = ['mousedown', 'touchstart'];
|
|
|
|
module.exports = function(ctrl) {
|
|
var fen = ctrl.computeFen();
|
|
var color = ctrl.chessground.data.orientation;
|
|
var opposite = color === 'white' ? 'black' : 'white';
|
|
return m('div.editor', {
|
|
config: function(el, isUpdate, context) {
|
|
if (isUpdate) return;
|
|
var onstart = partial(drag, ctrl);
|
|
eventNames.forEach(function(name) {
|
|
document.addEventListener(name, onstart);
|
|
});
|
|
context.onunload = function() {
|
|
eventNames.forEach(function(name) {
|
|
document.removeEventListener(name, onstart);
|
|
});
|
|
};
|
|
}
|
|
}, [
|
|
sparePieces(ctrl, opposite, color, 'top'),
|
|
chessground.view(ctrl.chessground),
|
|
sparePieces(ctrl, color, color, 'bottom'),
|
|
controls(ctrl, fen),
|
|
inputs(ctrl, fen)
|
|
]);
|
|
};
|