kokopu-react 1.7.1 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/Chessboard.js +84 -97
- package/dist/lib/ErrorBox.js +3 -1
- package/dist/lib/Movetext.js +24 -15
- package/dist/lib/i18n.js +2 -1
- package/dist/lib/impl/ArrowTip.js +2 -2
- package/dist/lib/impl/Motion.js +133 -0
- package/dist/lib/impl/util.js +12 -0
- package/doc_src/demo/PageChessboardInteraction.js +9 -9
- package/doc_src/demo/PageChessboardMove.js +8 -8
- package/doc_src/demo/PageMovetextInteraction.js +2 -2
- package/graphic_test_src/02_chessboard_simple.js +2 -2
- package/graphic_test_src/03_chessboard_flipped.js +2 -2
- package/graphic_test_src/05_chessboard_move.js +4 -4
- package/graphic_test_src/06a_chessboard_animated_move.js +36 -0
- package/graphic_test_src/06b_chessboard_animated_move.js +36 -0
- package/graphic_test_src/06c_chessboard_animated_move.js +36 -0
- package/graphic_test_src/{06_chessboard_theme.js → 07_chessboard_theme.js} +0 -0
- package/graphic_test_src/{07_chessboard_click_squares.js → 08_chessboard_click_squares.js} +0 -0
- package/graphic_test_src/{08_chessboard_move_pieces.js → 09_chessboard_move_pieces.js} +0 -0
- package/graphic_test_src/{09_chessboard_edit_arrows.js → 10_chessboard_edit_arrows.js} +0 -0
- package/graphic_test_src/{10_chessboard_play_moves.js → 11_chessboard_play_moves.js} +0 -0
- package/graphic_test_src/{11_chessboard_play_promotions.js → 12_chessboard_play_promotions.js} +0 -0
- package/graphic_test_src/{12_movetext_simple.js → 13_movetext_simple.js} +3 -3
- package/graphic_test_src/{13_movetext_error.js → 14_movetext_error.js} +4 -3
- package/graphic_test_src/{14_movetext_html.js → 15_movetext_html.js} +0 -0
- package/graphic_test_src/{15_movetext_options.js → 16_movetext_options.js} +0 -0
- package/graphic_test_src/{16_movetext_interaction.js → 17_movetext_interaction.js} +0 -0
- package/graphic_test_src/common/games.pgn +3 -3
- package/package.json +17 -19
- package/scripts/docker-compose.yml +1 -1
- package/src/Chessboard.js +42 -42
- package/src/ErrorBox.js +2 -1
- package/src/Movetext.js +20 -16
- package/src/i18n.js +1 -0
- package/src/impl/ArrowTip.js +2 -2
- package/src/impl/Motion.js +99 -0
- package/src/impl/util.js +8 -0
- package/test/4_chessboard_graphic.js +4 -1
- package/test/5_chessboard_interaction.js +5 -5
- package/test/6_chessboard_play_moves.js +4 -4
- package/test/7_movetext_graphic.js +4 -4
- package/test/8_movetext_interaction.js +2 -2
- package/test/common/graphic.js +6 -0
- package/test/references/06a_chessboard_animated_move/0.png +0 -0
- package/test/references/06a_chessboard_animated_move/1.png +0 -0
- package/test/references/06a_chessboard_animated_move/2.png +0 -0
- package/test/references/06a_chessboard_animated_move/3.png +0 -0
- package/test/references/06a_chessboard_animated_move/4.png +0 -0
- package/test/references/06a_chessboard_animated_move/5.png +0 -0
- package/test/references/06b_chessboard_animated_move/0.png +0 -0
- package/test/references/06b_chessboard_animated_move/1.png +0 -0
- package/test/references/06b_chessboard_animated_move/2.png +0 -0
- package/test/references/06b_chessboard_animated_move/3.png +0 -0
- package/test/references/06b_chessboard_animated_move/4.png +0 -0
- package/test/references/06b_chessboard_animated_move/5.png +0 -0
- package/test/references/06c_chessboard_animated_move/0.png +0 -0
- package/test/references/06c_chessboard_animated_move/1.png +0 -0
- package/test/references/06c_chessboard_animated_move/2.png +0 -0
- package/test/references/06c_chessboard_animated_move/3.png +0 -0
- package/test/references/06c_chessboard_animated_move/4.png +0 -0
- package/test/references/06c_chessboard_animated_move/5.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/0.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/1.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/2.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/3.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/4.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/5.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/6.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/7.png +0 -0
- package/test/references/{06_chessboard_theme → 07_chessboard_theme}/8.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/after_move.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/empty_square.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/null_vector.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/out_of_board.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_arrow_marker.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_empty.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_non_empty_1.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_non_empty_2.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_square_marker.png +0 -0
- package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_text_marker.png +0 -0
- package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/base_1.png +0 -0
- package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/base_2.png +0 -0
- package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/edit_color_not_set.png +0 -0
- package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/null_vector.png +0 -0
- package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/out_of_board.png +0 -0
- package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/over_arrow_marker.png +0 -0
- package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/over_square_marker.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/castling_move.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/chess960_ambiguous_king_move.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/chess960_castling_move_1.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/chess960_castling_move_2.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/chess960_non_kxr_castling.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/illegal_move.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/illegal_position.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/null_vector.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/out_of_board.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/regular_move_1.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/regular_move_2.png +0 -0
- package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/wrong_color.png +0 -0
- package/test/references/{11_chessboard_play_promotions → 12_chessboard_play_promotions}/antichess_promotion.png +0 -0
- package/test/references/{11_chessboard_play_promotions → 12_chessboard_play_promotions}/cancel_promotion.png +0 -0
- package/test/references/{11_chessboard_play_promotions → 12_chessboard_play_promotions}/regular_promotion_1.png +0 -0
- package/test/references/{11_chessboard_play_promotions → 12_chessboard_play_promotions}/regular_promotion_2.png +0 -0
- package/test/references/{12_movetext_simple → 13_movetext_simple}/0.png +0 -0
- package/test/references/{12_movetext_simple → 13_movetext_simple}/1.png +0 -0
- package/test/references/{12_movetext_simple → 13_movetext_simple}/2.png +0 -0
- package/test/references/{12_movetext_simple → 13_movetext_simple}/3.png +0 -0
- package/test/references/14_movetext_error/0.png +0 -0
- package/test/references/14_movetext_error/1.png +0 -0
- package/test/references/{13_movetext_error/1.png → 14_movetext_error/2.png} +0 -0
- package/test/references/14_movetext_error/3.png +0 -0
- package/test/references/14_movetext_error/4.png +0 -0
- package/test/references/15_movetext_html/0.png +0 -0
- package/test/references/15_movetext_html/1.png +0 -0
- package/test/references/{14_movetext_html → 15_movetext_html}/2.png +0 -0
- package/test/references/{15_movetext_options → 16_movetext_options}/0.png +0 -0
- package/test/references/{15_movetext_options → 16_movetext_options}/1.png +0 -0
- package/test/references/{15_movetext_options → 16_movetext_options}/2.png +0 -0
- package/test/references/{15_movetext_options → 16_movetext_options}/3.png +0 -0
- package/test/references/{16_movetext_interaction → 17_movetext_interaction}/0.png +0 -0
- package/test/references/{16_movetext_interaction → 17_movetext_interaction}/1.png +0 -0
- package/test/references/{16_movetext_interaction → 17_movetext_interaction}/2.png +0 -0
- package/CHANGELOG.md +0 -131
- package/graphics/chess_sprites/cburnett/bb.svg +0 -45
- package/graphics/chess_sprites/cburnett/bk.svg +0 -47
- package/graphics/chess_sprites/cburnett/bn.svg +0 -37
- package/graphics/chess_sprites/cburnett/bp.svg +0 -19
- package/graphics/chess_sprites/cburnett/bq.svg +0 -58
- package/graphics/chess_sprites/cburnett/br.svg +0 -60
- package/graphics/chess_sprites/cburnett/bx.svg +0 -56
- package/graphics/chess_sprites/cburnett/wb.svg +0 -48
- package/graphics/chess_sprites/cburnett/wk.svg +0 -26
- package/graphics/chess_sprites/cburnett/wn.svg +0 -37
- package/graphics/chess_sprites/cburnett/wp.svg +0 -19
- package/graphics/chess_sprites/cburnett/wq.svg +0 -60
- package/graphics/chess_sprites/cburnett/wr.svg +0 -44
- package/graphics/chess_sprites/cburnett/wx.svg +0 -56
- package/graphics/chess_sprites/generate_sprites.sh +0 -135
- package/graphics/chess_sprites/mmonge/celtic-bx.svg +0 -112
- package/graphics/chess_sprites/mmonge/celtic-wx.svg +0 -111
- package/graphics/chess_sprites/mmonge/celtic.svg +0 -1576
- package/graphics/chess_sprites/mmonge/eyes-spatial-bx.svg +0 -101
- package/graphics/chess_sprites/mmonge/eyes-spatial-wx.svg +0 -100
- package/graphics/chess_sprites/mmonge/eyes.svg +0 -2538
- package/graphics/chess_sprites/mmonge/fantasy-bx.svg +0 -112
- package/graphics/chess_sprites/mmonge/fantasy-wx.svg +0 -111
- package/graphics/chess_sprites/mmonge/fantasy.svg +0 -5497
- package/graphics/chess_sprites/mmonge/fantasy_alt.svg +0 -3742
- package/graphics/chess_sprites/mmonge/freak.svg +0 -3479
- package/graphics/chess_sprites/mmonge/prmi.svg +0 -6776
- package/graphics/chess_sprites/mmonge/skulls-bx.svg +0 -124
- package/graphics/chess_sprites/mmonge/skulls-wx.svg +0 -111
- package/graphics/chess_sprites/mmonge/skulls.svg +0 -12978
- package/graphics/chess_sprites/mmonge/spatial.svg +0 -1223
- package/graphics/logo-small.svg +0 -14
- package/graphics/logo.svg +0 -26
- package/test/references/13_movetext_error/0.png +0 -0
- package/test/references/13_movetext_error/2.png +0 -0
- package/test/references/13_movetext_error/3.png +0 -0
- package/test/references/14_movetext_html/0.png +0 -0
- package/test/references/14_movetext_html/1.png +0 -0
package/src/Chessboard.js
CHANGED
|
@@ -23,12 +23,12 @@
|
|
|
23
23
|
import PropTypes from 'prop-types';
|
|
24
24
|
import React from 'react';
|
|
25
25
|
import Draggable from 'react-draggable';
|
|
26
|
-
import {
|
|
27
|
-
import kokopu from 'kokopu';
|
|
26
|
+
import { exception, MoveDescriptor, Position, coordinatesToSquare, forEachSquare, oppositeColor, squareColor, squareToCoordinates } from 'kokopu';
|
|
28
27
|
|
|
29
28
|
import colorsets from './impl/colorsets';
|
|
30
29
|
import piecesets from './impl/piecesets';
|
|
31
30
|
import ArrowTip from './impl/ArrowTip';
|
|
31
|
+
import Motion from './impl/Motion';
|
|
32
32
|
import TextSymbol from './impl/TextSymbol';
|
|
33
33
|
import ErrorBox from './ErrorBox';
|
|
34
34
|
import i18n from './i18n';
|
|
@@ -45,7 +45,7 @@ const HOVER_MARKER_THICKNESS_FACTOR = 0.1;
|
|
|
45
45
|
const STROKE_THICKNESS_FACTOR = 0.15;
|
|
46
46
|
const ARROW_TIP_OFFSET_FACTOR = 0.3;
|
|
47
47
|
|
|
48
|
-
const
|
|
48
|
+
const MOTION_DURATION = 150;
|
|
49
49
|
|
|
50
50
|
const RANK_LABELS = '12345678';
|
|
51
51
|
const FILE_LABELS = 'abcdefgh';
|
|
@@ -67,15 +67,18 @@ export default class Chessboard extends React.Component {
|
|
|
67
67
|
windowWidth: window.innerWidth,
|
|
68
68
|
};
|
|
69
69
|
this.arrowTipIdSuffix = generateRandomId();
|
|
70
|
-
this.windowResizeListener = () => this.handleWindowResize();
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
componentDidMount() {
|
|
73
|
+
this.windowResizeListener = () => this.handleWindowResize();
|
|
74
74
|
window.addEventListener('resize', this.windowResizeListener);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
componentWillUnmount() {
|
|
78
|
-
|
|
78
|
+
if (this.windowResizeListener) {
|
|
79
|
+
window.removeEventListener('resize', this.windowResizeListener);
|
|
80
|
+
this.windowResizeListener = null;
|
|
81
|
+
}
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
render() {
|
|
@@ -102,7 +105,7 @@ export default class Chessboard extends React.Component {
|
|
|
102
105
|
|
|
103
106
|
// Render the squares.
|
|
104
107
|
let squares = [];
|
|
105
|
-
|
|
108
|
+
forEachSquare(sq => squares.push(this.renderSquare(squareSize, colorset, sq)));
|
|
106
109
|
|
|
107
110
|
// Render coordinates.
|
|
108
111
|
let rankCoordinates = [];
|
|
@@ -138,10 +141,11 @@ export default class Chessboard extends React.Component {
|
|
|
138
141
|
|
|
139
142
|
renderBoardContent(position, positionBefore, move, squareSize, colorset, pieceset) {
|
|
140
143
|
if (move && this.props.animated) {
|
|
144
|
+
let key = positionBefore.variant() + '|' + positionBefore.fen() + '|' + move.toString();
|
|
141
145
|
return (
|
|
142
|
-
<Motion key={
|
|
143
|
-
{
|
|
144
|
-
: this.renderBoardContentAnimated(positionBefore, move,
|
|
146
|
+
<Motion key={key} duration={MOTION_DURATION}>
|
|
147
|
+
{motionCursor => (motionCursor === 1 ? this.renderBoardContentStill(position, move, squareSize, colorset, pieceset)
|
|
148
|
+
: this.renderBoardContentAnimated(positionBefore, move, motionCursor, squareSize, colorset, pieceset))}
|
|
145
149
|
</Motion>
|
|
146
150
|
);
|
|
147
151
|
}
|
|
@@ -153,14 +157,14 @@ export default class Chessboard extends React.Component {
|
|
|
153
157
|
/**
|
|
154
158
|
* Render the board content during the animation.
|
|
155
159
|
*/
|
|
156
|
-
renderBoardContentAnimated(positionBefore, move,
|
|
160
|
+
renderBoardContentAnimated(positionBefore, move, motionCursor, squareSize, colorset, pieceset) {
|
|
157
161
|
let pieces = [];
|
|
158
|
-
|
|
162
|
+
forEachSquare(sq => pieces.push(this.renderPieceAnimated(positionBefore, move, motionCursor, squareSize, pieceset, sq)));
|
|
159
163
|
return (
|
|
160
164
|
<>
|
|
161
165
|
{pieces}
|
|
162
|
-
{this.renderMoveArrow(move,
|
|
163
|
-
{this.renderTurnFlag(
|
|
166
|
+
{this.renderMoveArrow(move, motionCursor, squareSize, colorset)}
|
|
167
|
+
{this.renderTurnFlag(oppositeColor(positionBefore.turn()), squareSize, pieceset)}
|
|
164
168
|
</>
|
|
165
169
|
);
|
|
166
170
|
}
|
|
@@ -178,7 +182,7 @@ export default class Chessboard extends React.Component {
|
|
|
178
182
|
// Render the square-related objects.
|
|
179
183
|
let pieces = [];
|
|
180
184
|
let handles = [];
|
|
181
|
-
|
|
185
|
+
forEachSquare(sq => {
|
|
182
186
|
pieces.push(this.renderPiece(position, squareSize, pieceset, sq));
|
|
183
187
|
if (this.props.interactionMode) {
|
|
184
188
|
handles.push(this.renderSquareHandle(position, squareSize, sq));
|
|
@@ -203,7 +207,7 @@ export default class Chessboard extends React.Component {
|
|
|
203
207
|
|
|
204
208
|
renderSquare(squareSize, colorset, sq) {
|
|
205
209
|
let { x, y } = this.getSquareCoordinates(squareSize, sq);
|
|
206
|
-
return <rect key={sq} x={x} y={y} width={squareSize} height={squareSize} fill={colorset[
|
|
210
|
+
return <rect key={sq} x={x} y={y} width={squareSize} height={squareSize} fill={colorset[squareColor(sq)]} />;
|
|
207
211
|
}
|
|
208
212
|
|
|
209
213
|
renderHoveredSquare(squareSize, colorset) {
|
|
@@ -226,7 +230,7 @@ export default class Chessboard extends React.Component {
|
|
|
226
230
|
return <image key={'piece-' + sq} x={x} y={y} width={squareSize} height={squareSize} href={pieceset[cp]} />;
|
|
227
231
|
}
|
|
228
232
|
|
|
229
|
-
renderPieceAnimated(positionBefore, move,
|
|
233
|
+
renderPieceAnimated(positionBefore, move, motionCursor, squareSize, pieceset, sq) {
|
|
230
234
|
let cp = positionBefore.square(sq);
|
|
231
235
|
if (cp === '-' || move.to() === sq || (move.isEnPassant() && move.enPassantSquare() === sq)) {
|
|
232
236
|
return undefined;
|
|
@@ -234,16 +238,16 @@ export default class Chessboard extends React.Component {
|
|
|
234
238
|
let { x, y } = this.getSquareCoordinates(squareSize, sq);
|
|
235
239
|
if (sq === move.from()) {
|
|
236
240
|
let { x: xTo, y: yTo } = this.getSquareCoordinates(squareSize, move.to());
|
|
237
|
-
x = xTo *
|
|
238
|
-
y = yTo *
|
|
239
|
-
if (move.isPromotion() &&
|
|
241
|
+
x = xTo * motionCursor + x * (1 - motionCursor);
|
|
242
|
+
y = yTo * motionCursor + y * (1 - motionCursor);
|
|
243
|
+
if (move.isPromotion() && motionCursor > 0.8) {
|
|
240
244
|
cp = move.coloredPromotion();
|
|
241
245
|
}
|
|
242
246
|
}
|
|
243
247
|
else if (move.isCastling() && sq === move.rookFrom()) {
|
|
244
248
|
let { x: xTo, y: yTo } = this.getSquareCoordinates(squareSize, move.rookTo());
|
|
245
|
-
x = xTo *
|
|
246
|
-
y = yTo *
|
|
249
|
+
x = xTo * motionCursor + x * (1 - motionCursor);
|
|
250
|
+
y = yTo * motionCursor + y * (1 - motionCursor);
|
|
247
251
|
}
|
|
248
252
|
return <image key={'piece-' + sq} x={x} y={y} width={squareSize} height={squareSize} href={pieceset[cp]} />;
|
|
249
253
|
}
|
|
@@ -384,8 +388,8 @@ export default class Chessboard extends React.Component {
|
|
|
384
388
|
return result;
|
|
385
389
|
}
|
|
386
390
|
|
|
387
|
-
renderMoveArrow(move,
|
|
388
|
-
if (!move ||
|
|
391
|
+
renderMoveArrow(move, motionCursor, squareSize, colorset) {
|
|
392
|
+
if (!move || motionCursor < 0.1 || !this.props.moveArrowVisible || move.from() === move.to()) {
|
|
389
393
|
return undefined;
|
|
390
394
|
}
|
|
391
395
|
let { x: xFrom, y: yFrom } = this.getSquareCoordinates(squareSize, move.from());
|
|
@@ -396,8 +400,8 @@ export default class Chessboard extends React.Component {
|
|
|
396
400
|
yTo += squareSize / 2;
|
|
397
401
|
xTo += Math.sign(xFrom - xTo) * ARROW_TIP_OFFSET_FACTOR * squareSize;
|
|
398
402
|
yTo += Math.sign(yFrom - yTo) * ARROW_TIP_OFFSET_FACTOR * squareSize;
|
|
399
|
-
let x = xTo *
|
|
400
|
-
let y = yTo *
|
|
403
|
+
let x = xTo * motionCursor + xFrom * (1 - motionCursor);
|
|
404
|
+
let y = yTo * motionCursor + yFrom * (1 - motionCursor);
|
|
401
405
|
let color = this.props.moveArrowColor;
|
|
402
406
|
return (
|
|
403
407
|
<line
|
|
@@ -575,7 +579,7 @@ export default class Chessboard extends React.Component {
|
|
|
575
579
|
* Return the (x,y) coordinates of the given square in the SVG canvas.
|
|
576
580
|
*/
|
|
577
581
|
getSquareCoordinates(squareSize, sq) {
|
|
578
|
-
let { file, rank } =
|
|
582
|
+
let { file, rank } = squareToCoordinates(sq);
|
|
579
583
|
let x = this.props.flipped ? (7 - file) * squareSize : file * squareSize;
|
|
580
584
|
let y = this.props.flipped ? rank * squareSize : (7 - rank) * squareSize;
|
|
581
585
|
return { x: x, y: y };
|
|
@@ -604,7 +608,7 @@ export default class Chessboard extends React.Component {
|
|
|
604
608
|
}
|
|
605
609
|
|
|
606
610
|
// Compute the position after the move and return the result.
|
|
607
|
-
let positionAfter = new
|
|
611
|
+
let positionAfter = new Position(positionInfo.position);
|
|
608
612
|
positionAfter.play(moveInfo.move);
|
|
609
613
|
return { positionError: false, moveError: false, positionBefore: positionInfo.position, move: moveInfo.move, position: positionAfter };
|
|
610
614
|
}
|
|
@@ -615,7 +619,7 @@ export default class Chessboard extends React.Component {
|
|
|
615
619
|
getSquareAt(squareSize, x, y) {
|
|
616
620
|
let file = this.props.flipped ? 7 - Math.floor(x / squareSize) : Math.floor(x / squareSize);
|
|
617
621
|
let rank = this.props.flipped ? Math.floor(y / squareSize) : 7 - Math.floor(y / squareSize);
|
|
618
|
-
return file >= 0 && file < 8 && rank >= 0 && rank < 8 ?
|
|
622
|
+
return file >= 0 && file < 8 && rank >= 0 && rank < 8 ? coordinatesToSquare(file, rank) : '-';
|
|
619
623
|
}
|
|
620
624
|
|
|
621
625
|
/**
|
|
@@ -760,30 +764,26 @@ export default class Chessboard extends React.Component {
|
|
|
760
764
|
Chessboard.propTypes = {
|
|
761
765
|
|
|
762
766
|
/**
|
|
763
|
-
* Displayed position. Can be a [kokopu.Position](https://kokopu.yo35.org/docs/Position.html) object,
|
|
767
|
+
* Displayed position. Can be a [kokopu.Position](https://kokopu.yo35.org/docs/current/classes/Position.html) object,
|
|
764
768
|
* a [FEN string](https://en.wikipedia.org/wiki/Forsyth%E2%80%93Edwards_Notation),
|
|
765
769
|
* `'start'` (usual starting position), or `'empty'` (empty board).
|
|
766
770
|
*
|
|
767
771
|
* Optionally, the FEN string can be prefixed with `'variant:'`, `variant` corresponding to one of the
|
|
768
|
-
* [game variant](https://kokopu.yo35.org/docs/
|
|
772
|
+
* [game variant](https://kokopu.yo35.org/docs/current/types/GameVariant.html) supported by Kokopu. For instance:
|
|
769
773
|
* `'chess960:nrkbqrbn/pppppppp/8/8/8/8/PPPPPPPP/NRKBQRBN w KQkq - 0 1'`.
|
|
770
774
|
*/
|
|
771
775
|
position: PropTypes.oneOfType([
|
|
772
|
-
PropTypes.instanceOf(
|
|
776
|
+
PropTypes.instanceOf(Position),
|
|
773
777
|
PropTypes.string
|
|
774
778
|
]),
|
|
775
779
|
|
|
776
780
|
/**
|
|
777
|
-
* Displayed move (optional), defined either as a [kokopu.MoveDescriptor](https://kokopu.yo35.org/docs/MoveDescriptor.html) object
|
|
781
|
+
* Displayed move (optional), defined either as a [kokopu.MoveDescriptor](https://kokopu.yo35.org/docs/current/classes/MoveDescriptor.html) object
|
|
778
782
|
* or as a [SAN string](https://en.wikipedia.org/wiki/Algebraic_notation_(chess)) (e.g. `'Nf3'`). In both cases, it must represent
|
|
779
783
|
* a legal move in position defined in attribute `position`.
|
|
780
784
|
*/
|
|
781
785
|
move: PropTypes.oneOfType([
|
|
782
|
-
|
|
783
|
-
if (!kokopu.isMoveDescriptor(props[propName])) {
|
|
784
|
-
return new Error(`Invalid prop ${propName} supplied to ${componentName}. Validation failed.`);
|
|
785
|
-
}
|
|
786
|
-
},
|
|
786
|
+
PropTypes.instanceOf(MoveDescriptor),
|
|
787
787
|
PropTypes.string
|
|
788
788
|
]),
|
|
789
789
|
|
|
@@ -961,16 +961,16 @@ function computeCoordinateFontSize(squareSize) {
|
|
|
961
961
|
* Try to interpret the given object as a chess position.
|
|
962
962
|
*/
|
|
963
963
|
function parsePosition(position) {
|
|
964
|
-
if (position instanceof
|
|
964
|
+
if (position instanceof Position) {
|
|
965
965
|
return { error: false, position: position };
|
|
966
966
|
}
|
|
967
967
|
else if (typeof position === 'string') {
|
|
968
968
|
try {
|
|
969
|
-
return { error: false, position: new
|
|
969
|
+
return { error: false, position: new Position(position) };
|
|
970
970
|
}
|
|
971
971
|
catch (e) {
|
|
972
972
|
// istanbul ignore else
|
|
973
|
-
if (e instanceof
|
|
973
|
+
if (e instanceof exception.InvalidFEN) {
|
|
974
974
|
return { error: true, message: e.message };
|
|
975
975
|
}
|
|
976
976
|
else {
|
|
@@ -988,7 +988,7 @@ function parsePosition(position) {
|
|
|
988
988
|
* Try to interpret the given object `move` as a move descriptor based on the given position.
|
|
989
989
|
*/
|
|
990
990
|
function parseMove(position, move) {
|
|
991
|
-
if (
|
|
991
|
+
if (move instanceof MoveDescriptor) {
|
|
992
992
|
return { error: false, move: move };
|
|
993
993
|
}
|
|
994
994
|
else if (typeof move === 'string') {
|
|
@@ -997,7 +997,7 @@ function parseMove(position, move) {
|
|
|
997
997
|
}
|
|
998
998
|
catch (e) {
|
|
999
999
|
// istanbul ignore else
|
|
1000
|
-
if (e instanceof
|
|
1000
|
+
if (e instanceof exception.InvalidNotation) {
|
|
1001
1001
|
return { error: true, message: e.message };
|
|
1002
1002
|
}
|
|
1003
1003
|
else {
|
package/src/ErrorBox.js
CHANGED
|
@@ -24,6 +24,7 @@ import PropTypes from 'prop-types';
|
|
|
24
24
|
import React from 'react';
|
|
25
25
|
|
|
26
26
|
import i18n from './i18n';
|
|
27
|
+
import { fillPlaceholder } from './impl/util';
|
|
27
28
|
|
|
28
29
|
import './css/error_box.css';
|
|
29
30
|
|
|
@@ -125,7 +126,7 @@ function ellipsisAt(text, pos, backwardCharacters, forwardCharacters, lineNumber
|
|
|
125
126
|
excerpt = excerpt.replace(/\n|\r|\t/g, ' ');
|
|
126
127
|
let secondLine = Array(1 + e1.length + pos - p1).join(' ') + '^';
|
|
127
128
|
if (lineNumber) {
|
|
128
|
-
secondLine +=
|
|
129
|
+
secondLine += ` (${fillPlaceholder(i18n.LINE, lineNumber)})`;
|
|
129
130
|
}
|
|
130
131
|
return excerpt + '\n' + secondLine;
|
|
131
132
|
}
|
package/src/Movetext.js
CHANGED
|
@@ -22,9 +22,10 @@
|
|
|
22
22
|
|
|
23
23
|
import PropTypes from 'prop-types';
|
|
24
24
|
import React from 'react';
|
|
25
|
-
import
|
|
25
|
+
import { exception, Database, Game, nagSymbol, pgnRead } from 'kokopu';
|
|
26
26
|
|
|
27
27
|
import HtmlSanitizer from './impl/HtmlSanitizer';
|
|
28
|
+
import { fillPlaceholder } from './impl/util';
|
|
28
29
|
import Chessboard from './Chessboard';
|
|
29
30
|
import ErrorBox from './ErrorBox';
|
|
30
31
|
import { moveFormatter } from './formatmove';
|
|
@@ -85,7 +86,7 @@ export default class Movetext extends React.Component {
|
|
|
85
86
|
let colorTag = <span className="kokopu-colorTag"></span>;
|
|
86
87
|
let playerNameElement = <span className="kokopu-header-playerName">{sanitizeHtml(playerName)}</span>;
|
|
87
88
|
let titleElement = title === undefined ? undefined : <span className="kokopu-header-playerTitle">{sanitizeHtml(title)}</span>;
|
|
88
|
-
let ratingElement = rating === undefined ? undefined : <span className="kokopu-header-playerRating">{
|
|
89
|
+
let ratingElement = rating === undefined ? undefined : <span className="kokopu-header-playerRating">{rating}</span>;
|
|
89
90
|
let separator = title === undefined || rating === undefined ? undefined : '\u00a0'; // \u00a0 ==
|
|
90
91
|
let titleRatingGroup = title === undefined && rating === undefined ? undefined : <span className="kokopu-headerGroup-titleRating">{titleElement}{separator}{ratingElement}</span>;
|
|
91
92
|
return <div className={classNames.join(' ')} key={'player-' + color}>{colorTag}{playerNameElement}{titleRatingGroup}</div>;
|
|
@@ -128,7 +129,7 @@ export default class Movetext extends React.Component {
|
|
|
128
129
|
if (annotator === undefined) {
|
|
129
130
|
return undefined;
|
|
130
131
|
}
|
|
131
|
-
annotator = i18n.ANNOTATED_BY
|
|
132
|
+
annotator = fillPlaceholder(i18n.ANNOTATED_BY, annotator);
|
|
132
133
|
return <div className="kokopu-header-annotator" key="annotator">{sanitizeHtml(annotator)}</div>;
|
|
133
134
|
}
|
|
134
135
|
|
|
@@ -255,7 +256,7 @@ export default class Movetext extends React.Component {
|
|
|
255
256
|
let notationText = notationTextBuilder(node.notation());
|
|
256
257
|
|
|
257
258
|
// NAGs
|
|
258
|
-
let nagElements = node.nags().map(nag => <span className="kokopu-nag" key={nag}>{
|
|
259
|
+
let nagElements = node.nags().map(nag => <span className="kokopu-nag" key={nag}>{nagSymbol(nag)}</span>);
|
|
259
260
|
|
|
260
261
|
// Class
|
|
261
262
|
let nodeId = node.id();
|
|
@@ -482,18 +483,18 @@ export default class Movetext extends React.Component {
|
|
|
482
483
|
Movetext.propTypes = {
|
|
483
484
|
|
|
484
485
|
/**
|
|
485
|
-
* Displayed position. Can be a [kokopu.Game](https://kokopu.yo35.org/docs/Game.html) object,
|
|
486
|
-
* a [kokopu.Database](https://kokopu.yo35.org/docs/Database.html) object,
|
|
486
|
+
* Displayed position. Can be a [kokopu.Game](https://kokopu.yo35.org/docs/current/classes/Game.html) object,
|
|
487
|
+
* a [kokopu.Database](https://kokopu.yo35.org/docs/current/classes/Database.html) object,
|
|
487
488
|
* or a [PGN string](https://en.wikipedia.org/wiki/Portable_Game_Notation).
|
|
488
489
|
*/
|
|
489
490
|
game: PropTypes.oneOfType([
|
|
490
|
-
PropTypes.instanceOf(
|
|
491
|
-
PropTypes.instanceOf(
|
|
491
|
+
PropTypes.instanceOf(Game),
|
|
492
|
+
PropTypes.instanceOf(Database),
|
|
492
493
|
PropTypes.string
|
|
493
494
|
]),
|
|
494
495
|
|
|
495
496
|
/**
|
|
496
|
-
* Index of the game to display (only if attribute `game` is a [kokopu.Database](https://kokopu.yo35.org/docs/Database.html)
|
|
497
|
+
* Index of the game to display (only if attribute `game` is a [kokopu.Database](https://kokopu.yo35.org/docs/current/classes/Database.html)
|
|
497
498
|
* or a [PGN string](https://en.wikipedia.org/wiki/Portable_Game_Notation)): `0` for the first game of the database/PGN, `1` for the second one, etc.
|
|
498
499
|
* If omitted, the first game of the database/PGN is displayed.
|
|
499
500
|
*/
|
|
@@ -542,7 +543,7 @@ Movetext.propTypes = {
|
|
|
542
543
|
|
|
543
544
|
/**
|
|
544
545
|
* ID of the selected move (or `'start'` for the beginning of the main variation).
|
|
545
|
-
* Use [kokopu.Node#id](https://kokopu.yo35.org/docs/Node.html#id) to get the ID of a game move.
|
|
546
|
+
* Use [kokopu.Node#id](https://kokopu.yo35.org/docs/current/classes/Node.html#id) to get the ID of a game move.
|
|
546
547
|
*/
|
|
547
548
|
selection: PropTypes.string,
|
|
548
549
|
|
|
@@ -556,7 +557,7 @@ Movetext.propTypes = {
|
|
|
556
557
|
/**
|
|
557
558
|
* Callback invoked when the user selects a move (only if `interactionMode` is set to `'selectMove'`).
|
|
558
559
|
*
|
|
559
|
-
* @param {string?} nodeId ID of the selected move (as returned by [kokopu.Node#id](https://kokopu.yo35.org/docs/Node.html#id)),
|
|
560
|
+
* @param {string?} nodeId ID of the selected move (as returned by [kokopu.Node#id](https://kokopu.yo35.org/docs/current/classes/Node.html#id)),
|
|
560
561
|
* `'start'` for the beginning of the main variation, or `undefined` if the user unselects the previously selected move.
|
|
561
562
|
* @param {string} evtOrigin Origin of the event. Can be:
|
|
562
563
|
* - `'key-first'`: the event has been triggered by the "go-to-first-move" key (aka. the home key),
|
|
@@ -570,7 +571,7 @@ Movetext.propTypes = {
|
|
|
570
571
|
|
|
571
572
|
|
|
572
573
|
Movetext.defaultProps = {
|
|
573
|
-
game: new
|
|
574
|
+
game: new Game(),
|
|
574
575
|
gameIndex: 0,
|
|
575
576
|
diagramOptions: {},
|
|
576
577
|
pieceSymbols: 'native',
|
|
@@ -643,17 +644,20 @@ function sanitizeHtml(text, sanitizer) {
|
|
|
643
644
|
* Try to interpret the given object as a chess game.
|
|
644
645
|
*/
|
|
645
646
|
function parseGame(game, gameIndex) {
|
|
646
|
-
if (game instanceof
|
|
647
|
+
if (game instanceof Game) {
|
|
647
648
|
return { error: false, game: game };
|
|
648
649
|
}
|
|
649
|
-
else if (game instanceof
|
|
650
|
+
else if (game instanceof Database || typeof game === 'string') {
|
|
651
|
+
if (!Number.isInteger(gameIndex) || gameIndex < 0) {
|
|
652
|
+
return { error: true, message: i18n.INVALID_GAME_INDEX_ATTRIBUTE_ERROR_MESSAGE };
|
|
653
|
+
}
|
|
650
654
|
try {
|
|
651
|
-
|
|
655
|
+
const result = game instanceof Database ? game.game(gameIndex) : pgnRead(game, gameIndex);
|
|
652
656
|
return { error: false, game: result };
|
|
653
657
|
}
|
|
654
658
|
catch (e) {
|
|
655
659
|
// istanbul ignore else
|
|
656
|
-
if (e instanceof
|
|
660
|
+
if (e instanceof exception.InvalidPGN) {
|
|
657
661
|
return { error: true, message: e.message, text: e.pgn, errorIndex: e.index, lineNumber: e.lineNumber };
|
|
658
662
|
}
|
|
659
663
|
else {
|
package/src/i18n.js
CHANGED
|
@@ -36,6 +36,7 @@ const i18n = {
|
|
|
36
36
|
ANNOTATED_BY: 'Annotated by {0}',
|
|
37
37
|
INVALID_PGN_ERROR_TITLE: 'Invalid PGN string.',
|
|
38
38
|
INVALID_GAME_ATTRIBUTE_ERROR_MESSAGE: 'Invalid "game" attribute.',
|
|
39
|
+
INVALID_GAME_INDEX_ATTRIBUTE_ERROR_MESSAGE: 'Invalid "game index" attribute.',
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
export default i18n;
|
package/src/impl/ArrowTip.js
CHANGED
|
@@ -29,8 +29,8 @@ import React from 'react';
|
|
|
29
29
|
*/
|
|
30
30
|
export default function ArrowTip(props) {
|
|
31
31
|
return (
|
|
32
|
-
<marker id={props.id} markerWidth={4} markerHeight={4} refX={2.5} refY={2} orient="auto"
|
|
33
|
-
<path d="M 4,2 L 0,4 L 1,2 L 0,0 Z" />
|
|
32
|
+
<marker id={props.id} markerWidth={4} markerHeight={4} refX={2.5} refY={2} orient="auto">
|
|
33
|
+
<path fill={props.color} d="M 4,2 L 0,4 L 1,2 L 0,0 Z" />
|
|
34
34
|
</marker>
|
|
35
35
|
);
|
|
36
36
|
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/******************************************************************************
|
|
2
|
+
* *
|
|
3
|
+
* This file is part of Kokopu-React, a JavaScript chess library. *
|
|
4
|
+
* Copyright (C) 2021-2022 Yoann Le Montagner <yo35 -at- melix.net> *
|
|
5
|
+
* *
|
|
6
|
+
* This program is free software: you can redistribute it and/or *
|
|
7
|
+
* modify it under the terms of the GNU Lesser General Public License *
|
|
8
|
+
* as published by the Free Software Foundation, either version 3 of *
|
|
9
|
+
* the License, or (at your option) any later version. *
|
|
10
|
+
* *
|
|
11
|
+
* This program is distributed in the hope that it will be useful, *
|
|
12
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
13
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
14
|
+
* GNU Lesser General Public License for more details. *
|
|
15
|
+
* *
|
|
16
|
+
* You should have received a copy of the GNU Lesser General *
|
|
17
|
+
* Public License along with this program. If not, see *
|
|
18
|
+
* <http://www.gnu.org/licenses/>. *
|
|
19
|
+
* *
|
|
20
|
+
******************************************************************************/
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
import PropTypes from 'prop-types';
|
|
24
|
+
import React from 'react';
|
|
25
|
+
|
|
26
|
+
const DEBUG_KEY = '__kokopu_debug_freeze_motion';
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Wrap some animated content.
|
|
31
|
+
*/
|
|
32
|
+
export default class Motion extends React.Component {
|
|
33
|
+
|
|
34
|
+
constructor(props) {
|
|
35
|
+
super(props);
|
|
36
|
+
this.state = {
|
|
37
|
+
cursor: 0,
|
|
38
|
+
};
|
|
39
|
+
this.animationFrameId = null;
|
|
40
|
+
this.cursorStop = 1;
|
|
41
|
+
|
|
42
|
+
// WARNING: this hack exists only for testing purposes. DO NOT USE IT IN PRODUCTION.
|
|
43
|
+
if (typeof window[DEBUG_KEY] === 'number' && window[DEBUG_KEY] >= 0 && window[DEBUG_KEY] <= 1) {
|
|
44
|
+
this.cursorStop = window[DEBUG_KEY];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
componentDidMount() {
|
|
49
|
+
this.animationFrameId = window.requestAnimationFrame(ts => this.handleAnimationStep(ts));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
componentWillUnmount() {
|
|
53
|
+
if (this.animationFrameId !== null) {
|
|
54
|
+
window.cancelAnimationFrame(this.animationFrameId);
|
|
55
|
+
this.animationFrameId = null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
handleAnimationStep(timestamp) {
|
|
60
|
+
if (this.initialTimestamp === undefined) {
|
|
61
|
+
this.initialTimestamp = timestamp;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Compute the animation cursor and update the state.
|
|
65
|
+
let cursor = (timestamp - this.initialTimestamp) / this.props.duration;
|
|
66
|
+
if (cursor < 0) {
|
|
67
|
+
cursor = 0;
|
|
68
|
+
}
|
|
69
|
+
else if (cursor > this.cursorStop) {
|
|
70
|
+
cursor = this.cursorStop;
|
|
71
|
+
}
|
|
72
|
+
this.setState({ cursor: cursor });
|
|
73
|
+
|
|
74
|
+
// Schedule the next animation frame if necessary.
|
|
75
|
+
if (cursor === this.cursorStop) {
|
|
76
|
+
this.animationFrameId = null;
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
this.animationFrameId = window.requestAnimationFrame(ts => this.handleAnimationStep(ts));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
render() {
|
|
84
|
+
return this.props.children(this.state.cursor);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
Motion.propTypes = {
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Duration of the animation. Must be > 0.
|
|
92
|
+
*/
|
|
93
|
+
duration: PropTypes.number.isRequired,
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Factory for the content being animated. The animation cursor is guaranteed to be valued between 0 and 1 inclusive.
|
|
97
|
+
*/
|
|
98
|
+
children: PropTypes.func.isRequired,
|
|
99
|
+
};
|
package/src/impl/util.js
CHANGED
|
@@ -35,6 +35,14 @@ export function generateRandomId() {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
|
|
38
|
+
export function fillPlaceholder(message, ...placeholderValues) {
|
|
39
|
+
return message.replace(/{(\d+)}/g, (match, placeholder) => {
|
|
40
|
+
const placeholderIndex = Number(placeholder);
|
|
41
|
+
return placeholderIndex < placeholderValues.length ? placeholderValues[placeholderIndex] : match;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
38
46
|
export function sanitizeInteger(input, min, max) {
|
|
39
47
|
return Math.min(Math.max(Math.round(input), min), max);
|
|
40
48
|
}
|
|
@@ -41,6 +41,9 @@ describe('Chessboard graphic', function() {
|
|
|
41
41
|
'overlap', 'overlap & flip' ]);
|
|
42
42
|
itChecksScreenshots(browserContext, '05_chessboard_move', [ 'default', 'no move arrow', 'invalid', 'with forced move arrow & flip', 'capture', 'castling move',
|
|
43
43
|
'en-passant', 'promotion', 'wrong type' ]);
|
|
44
|
-
itChecksScreenshots(browserContext, '
|
|
44
|
+
itChecksScreenshots(browserContext, '06a_chessboard_animated_move', [ 'move 1', 'move 2', 'capture', 'castling move', 'en-pssant', 'promotion' ]);
|
|
45
|
+
itChecksScreenshots(browserContext, '06b_chessboard_animated_move', [ 'move 1', 'move 2', 'capture', 'castling move', 'en-pssant', 'promotion' ]);
|
|
46
|
+
itChecksScreenshots(browserContext, '06c_chessboard_animated_move', [ 'move 1', 'move 2', 'capture', 'castling move', 'en-pssant', 'promotion' ]);
|
|
47
|
+
itChecksScreenshots(browserContext, '07_chessboard_theme', [ 'default', 'large', 'small', 'custom 1', 'custom 2', 'custom 3',
|
|
45
48
|
'custom 4', 'custom 5', 'custom 6' ]);
|
|
46
49
|
});
|
|
@@ -36,7 +36,7 @@ describe('Chessboard interaction', function() {
|
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
function itCheckClickSquare(itemIndex, label, targets) {
|
|
39
|
-
itCustom(browserContext, '
|
|
39
|
+
itCustom(browserContext, '08_chessboard_click_squares', itemIndex, label, async function(element) {
|
|
40
40
|
let actions = browserContext.driver.actions({ async: true });
|
|
41
41
|
let area = await element.getRect();
|
|
42
42
|
for (let i = 0; i < targets.length; ++i) {
|
|
@@ -63,7 +63,7 @@ describe('Chessboard interaction', function() {
|
|
|
63
63
|
]);
|
|
64
64
|
|
|
65
65
|
function itCheckMovePiece(itemIndex, label, xFrom, yFrom, xTo, yTo, imageBaseName, expectedText) {
|
|
66
|
-
itCustom(browserContext, '
|
|
66
|
+
itCustom(browserContext, '09_chessboard_move_pieces', itemIndex, label, async function(element) {
|
|
67
67
|
let actions = browserContext.driver.actions({ async: true });
|
|
68
68
|
let area = await element.getRect();
|
|
69
69
|
await actions.move({ x: area.x + xFrom, y: area.y + yFrom }).press().move({ x: area.x + xTo, y: area.y + yTo }).perform();
|
|
@@ -83,7 +83,7 @@ describe('Chessboard interaction', function() {
|
|
|
83
83
|
itCheckMovePiece(2, 'after move', 225, 225, 75, 260, 'after_move', 'piece moved: e4 -> b3');
|
|
84
84
|
|
|
85
85
|
function itCheckNonMovePiece(itemIndex, label, xFrom, yFrom, xTo, yTo, imageBaseName) {
|
|
86
|
-
itCustom(browserContext, '
|
|
86
|
+
itCustom(browserContext, '09_chessboard_move_pieces', itemIndex, label, async function(element) {
|
|
87
87
|
await setSandbox(browserContext, imageBaseName); // can be any value as long as it is unique among other test-cases
|
|
88
88
|
let actions = browserContext.driver.actions({ async: true });
|
|
89
89
|
let area = await element.getRect();
|
|
@@ -100,7 +100,7 @@ describe('Chessboard interaction', function() {
|
|
|
100
100
|
itCheckNonMovePiece(0, 'out of board', 175, 25, 500, 210, 'out_of_board');
|
|
101
101
|
|
|
102
102
|
function itCheckEditArrow(itemIndex, label, xFrom, yFrom, xTo, yTo, imageBaseName, expectedText) {
|
|
103
|
-
itCustom(browserContext, '
|
|
103
|
+
itCustom(browserContext, '10_chessboard_edit_arrows', itemIndex, label, async function(element) {
|
|
104
104
|
let actions = browserContext.driver.actions({ async: true });
|
|
105
105
|
let area = await element.getRect();
|
|
106
106
|
await actions.move({ x: area.x + xFrom, y: area.y + yFrom }).press().move({ x: area.x + xTo, y: area.y + yTo }).perform();
|
|
@@ -117,7 +117,7 @@ describe('Chessboard interaction', function() {
|
|
|
117
117
|
itCheckEditArrow(1, 'over arrow marker', 40, 110, 125, 290, 'over_arrow_marker', 'arrow edited: h3 -> f6');
|
|
118
118
|
|
|
119
119
|
function itCheckNonEditArrow(itemIndex, label, xFrom, yFrom, xTo, yTo, imageBaseName) {
|
|
120
|
-
itCustom(browserContext, '
|
|
120
|
+
itCustom(browserContext, '10_chessboard_edit_arrows', itemIndex, label, async function(element) {
|
|
121
121
|
await setSandbox(browserContext, imageBaseName); // can be any value as long as it is unique among other test-cases
|
|
122
122
|
let actions = browserContext.driver.actions({ async: true });
|
|
123
123
|
let area = await element.getRect();
|
|
@@ -36,7 +36,7 @@ describe('Chessboard play moves', function() {
|
|
|
36
36
|
});
|
|
37
37
|
|
|
38
38
|
function itCheckPlayMove(itemIndex, label, xFrom, yFrom, xTo, yTo, imageBaseName, expectedText) {
|
|
39
|
-
itCustom(browserContext, '
|
|
39
|
+
itCustom(browserContext, '11_chessboard_play_moves', itemIndex, label, async function(element) {
|
|
40
40
|
let actions = browserContext.driver.actions({ async: true });
|
|
41
41
|
let area = await element.getRect();
|
|
42
42
|
await actions.move({ x: area.x + xFrom, y: area.y + yFrom }).press().move({ x: area.x + xTo, y: area.y + yTo }).perform();
|
|
@@ -55,7 +55,7 @@ describe('Chessboard play moves', function() {
|
|
|
55
55
|
itCheckPlayMove(3, 'chess960 ambiguous king move', 275, 375, 320, 375, 'chess960_ambiguous_king_move', 'move played: Kg1');
|
|
56
56
|
|
|
57
57
|
function itCheckNonPlayMove(itemIndex, label, xFrom, yFrom, xTo, yTo, imageBaseName) {
|
|
58
|
-
itCustom(browserContext, '
|
|
58
|
+
itCustom(browserContext, '11_chessboard_play_moves', itemIndex, label, async function(element) {
|
|
59
59
|
await setSandbox(browserContext, imageBaseName); // can be any value as long as it is unique among other test-cases
|
|
60
60
|
let actions = browserContext.driver.actions({ async: true });
|
|
61
61
|
let area = await element.getRect();
|
|
@@ -75,7 +75,7 @@ describe('Chessboard play moves', function() {
|
|
|
75
75
|
itCheckNonPlayMove(3, 'chess960 non-KxR castling', 275, 375, 130, 375, 'chess960_non_kxr_castling');
|
|
76
76
|
|
|
77
77
|
function itCheckPlayPromotion(itemIndex, label, xFrom, yFrom, xTo, yTo, xPromo, yPromo, imageBaseName, expectedText) {
|
|
78
|
-
itCustom(browserContext, '
|
|
78
|
+
itCustom(browserContext, '12_chessboard_play_promotions', itemIndex, label, async function(element) {
|
|
79
79
|
let actions = browserContext.driver.actions({ async: true });
|
|
80
80
|
let area = await element.getRect();
|
|
81
81
|
await actions.move({ x: area.x + xFrom, y: area.y + yFrom }).press().move({ x: area.x + xTo, y: area.y + yTo }).release().perform();
|
|
@@ -91,7 +91,7 @@ describe('Chessboard play moves', function() {
|
|
|
91
91
|
itCheckPlayPromotion(2, 'antichess promotion', 325, 325, 325, 375, 325, 175, 'antichess_promotion', 'promotion move played: b8=K');
|
|
92
92
|
|
|
93
93
|
function itCheckNonPlayPromotion(itemIndex, label, xFrom, yFrom, xTo, yTo, xPromo, yPromo, imageBaseName) {
|
|
94
|
-
itCustom(browserContext, '
|
|
94
|
+
itCustom(browserContext, '12_chessboard_play_promotions', itemIndex, label, async function(element) {
|
|
95
95
|
await setSandbox(browserContext, imageBaseName); // can be any value as long as it is unique among other test-cases
|
|
96
96
|
let actions = browserContext.driver.actions({ async: true });
|
|
97
97
|
let area = await element.getRect();
|
|
@@ -35,9 +35,9 @@ describe('Movetext graphic', function() {
|
|
|
35
35
|
await closeBrowser(browserContext);
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
-
itChecksScreenshots(browserContext, '
|
|
39
|
-
itChecksScreenshots(browserContext, '
|
|
40
|
-
itChecksScreenshots(browserContext, '
|
|
41
|
-
itChecksScreenshots(browserContext, '
|
|
38
|
+
itChecksScreenshots(browserContext, '13_movetext_simple', [ 'game-0', 'game-1', 'game-2', 'game-3' ]);
|
|
39
|
+
itChecksScreenshots(browserContext, '14_movetext_error', [ 'wrong-game-index-1', 'wrong-game-index-2', 'pgn-parsing-error-1', 'pgn-parsing-error-2', 'wrong type' ]);
|
|
40
|
+
itChecksScreenshots(browserContext, '15_movetext_html', [ 'html-in-headers', 'html-in-comments', 'filtered-tags-and-attributes' ]);
|
|
41
|
+
itChecksScreenshots(browserContext, '16_movetext_options', [ 'localized-piece-symbols', 'custom-piece-symbols', 'figurine-piece-symbols-and-diagram-options',
|
|
42
42
|
'hidden-diagrams' ]);
|
|
43
43
|
});
|
|
@@ -37,7 +37,7 @@ describe('Movetext interaction', function() {
|
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
function itCheckClickMove(itemIndex, label, targets) {
|
|
40
|
-
itCustom(browserContext, '
|
|
40
|
+
itCustom(browserContext, '17_movetext_interaction', itemIndex, label, async function(element) {
|
|
41
41
|
let actions = browserContext.driver.actions({ async: true });
|
|
42
42
|
await setSandbox(browserContext, '');
|
|
43
43
|
for (let i = 0; i < targets.length; ++i) {
|
|
@@ -72,7 +72,7 @@ describe('Movetext interaction', function() {
|
|
|
72
72
|
]);
|
|
73
73
|
|
|
74
74
|
function itCheckKeyboardActions(itemIndex, label, expectedOnGoFirst, expectedOnGoPrevious, expectedOnGoNext, expectedOnGoLast) {
|
|
75
|
-
itCustom(browserContext, '
|
|
75
|
+
itCustom(browserContext, '17_movetext_interaction', itemIndex, label, async function(element) {
|
|
76
76
|
let focusFieldElement = await element.findElement(By.className('kokopu-focusField'));
|
|
77
77
|
|
|
78
78
|
await setSandbox(browserContext, '');
|