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.
Files changed (161) hide show
  1. package/dist/lib/Chessboard.js +84 -97
  2. package/dist/lib/ErrorBox.js +3 -1
  3. package/dist/lib/Movetext.js +24 -15
  4. package/dist/lib/i18n.js +2 -1
  5. package/dist/lib/impl/ArrowTip.js +2 -2
  6. package/dist/lib/impl/Motion.js +133 -0
  7. package/dist/lib/impl/util.js +12 -0
  8. package/doc_src/demo/PageChessboardInteraction.js +9 -9
  9. package/doc_src/demo/PageChessboardMove.js +8 -8
  10. package/doc_src/demo/PageMovetextInteraction.js +2 -2
  11. package/graphic_test_src/02_chessboard_simple.js +2 -2
  12. package/graphic_test_src/03_chessboard_flipped.js +2 -2
  13. package/graphic_test_src/05_chessboard_move.js +4 -4
  14. package/graphic_test_src/06a_chessboard_animated_move.js +36 -0
  15. package/graphic_test_src/06b_chessboard_animated_move.js +36 -0
  16. package/graphic_test_src/06c_chessboard_animated_move.js +36 -0
  17. package/graphic_test_src/{06_chessboard_theme.js → 07_chessboard_theme.js} +0 -0
  18. package/graphic_test_src/{07_chessboard_click_squares.js → 08_chessboard_click_squares.js} +0 -0
  19. package/graphic_test_src/{08_chessboard_move_pieces.js → 09_chessboard_move_pieces.js} +0 -0
  20. package/graphic_test_src/{09_chessboard_edit_arrows.js → 10_chessboard_edit_arrows.js} +0 -0
  21. package/graphic_test_src/{10_chessboard_play_moves.js → 11_chessboard_play_moves.js} +0 -0
  22. package/graphic_test_src/{11_chessboard_play_promotions.js → 12_chessboard_play_promotions.js} +0 -0
  23. package/graphic_test_src/{12_movetext_simple.js → 13_movetext_simple.js} +3 -3
  24. package/graphic_test_src/{13_movetext_error.js → 14_movetext_error.js} +4 -3
  25. package/graphic_test_src/{14_movetext_html.js → 15_movetext_html.js} +0 -0
  26. package/graphic_test_src/{15_movetext_options.js → 16_movetext_options.js} +0 -0
  27. package/graphic_test_src/{16_movetext_interaction.js → 17_movetext_interaction.js} +0 -0
  28. package/graphic_test_src/common/games.pgn +3 -3
  29. package/package.json +17 -19
  30. package/scripts/docker-compose.yml +1 -1
  31. package/src/Chessboard.js +42 -42
  32. package/src/ErrorBox.js +2 -1
  33. package/src/Movetext.js +20 -16
  34. package/src/i18n.js +1 -0
  35. package/src/impl/ArrowTip.js +2 -2
  36. package/src/impl/Motion.js +99 -0
  37. package/src/impl/util.js +8 -0
  38. package/test/4_chessboard_graphic.js +4 -1
  39. package/test/5_chessboard_interaction.js +5 -5
  40. package/test/6_chessboard_play_moves.js +4 -4
  41. package/test/7_movetext_graphic.js +4 -4
  42. package/test/8_movetext_interaction.js +2 -2
  43. package/test/common/graphic.js +6 -0
  44. package/test/references/06a_chessboard_animated_move/0.png +0 -0
  45. package/test/references/06a_chessboard_animated_move/1.png +0 -0
  46. package/test/references/06a_chessboard_animated_move/2.png +0 -0
  47. package/test/references/06a_chessboard_animated_move/3.png +0 -0
  48. package/test/references/06a_chessboard_animated_move/4.png +0 -0
  49. package/test/references/06a_chessboard_animated_move/5.png +0 -0
  50. package/test/references/06b_chessboard_animated_move/0.png +0 -0
  51. package/test/references/06b_chessboard_animated_move/1.png +0 -0
  52. package/test/references/06b_chessboard_animated_move/2.png +0 -0
  53. package/test/references/06b_chessboard_animated_move/3.png +0 -0
  54. package/test/references/06b_chessboard_animated_move/4.png +0 -0
  55. package/test/references/06b_chessboard_animated_move/5.png +0 -0
  56. package/test/references/06c_chessboard_animated_move/0.png +0 -0
  57. package/test/references/06c_chessboard_animated_move/1.png +0 -0
  58. package/test/references/06c_chessboard_animated_move/2.png +0 -0
  59. package/test/references/06c_chessboard_animated_move/3.png +0 -0
  60. package/test/references/06c_chessboard_animated_move/4.png +0 -0
  61. package/test/references/06c_chessboard_animated_move/5.png +0 -0
  62. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/0.png +0 -0
  63. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/1.png +0 -0
  64. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/2.png +0 -0
  65. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/3.png +0 -0
  66. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/4.png +0 -0
  67. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/5.png +0 -0
  68. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/6.png +0 -0
  69. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/7.png +0 -0
  70. package/test/references/{06_chessboard_theme → 07_chessboard_theme}/8.png +0 -0
  71. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/after_move.png +0 -0
  72. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/empty_square.png +0 -0
  73. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/null_vector.png +0 -0
  74. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/out_of_board.png +0 -0
  75. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_arrow_marker.png +0 -0
  76. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_empty.png +0 -0
  77. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_non_empty_1.png +0 -0
  78. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_non_empty_2.png +0 -0
  79. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_square_marker.png +0 -0
  80. package/test/references/{08_chessboard_move_pieces → 09_chessboard_move_pieces}/over_text_marker.png +0 -0
  81. package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/base_1.png +0 -0
  82. package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/base_2.png +0 -0
  83. package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/edit_color_not_set.png +0 -0
  84. package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/null_vector.png +0 -0
  85. package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/out_of_board.png +0 -0
  86. package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/over_arrow_marker.png +0 -0
  87. package/test/references/{09_chessboard_edit_arrows → 10_chessboard_edit_arrows}/over_square_marker.png +0 -0
  88. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/castling_move.png +0 -0
  89. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/chess960_ambiguous_king_move.png +0 -0
  90. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/chess960_castling_move_1.png +0 -0
  91. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/chess960_castling_move_2.png +0 -0
  92. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/chess960_non_kxr_castling.png +0 -0
  93. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/illegal_move.png +0 -0
  94. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/illegal_position.png +0 -0
  95. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/null_vector.png +0 -0
  96. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/out_of_board.png +0 -0
  97. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/regular_move_1.png +0 -0
  98. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/regular_move_2.png +0 -0
  99. package/test/references/{10_chessboard_play_moves → 11_chessboard_play_moves}/wrong_color.png +0 -0
  100. package/test/references/{11_chessboard_play_promotions → 12_chessboard_play_promotions}/antichess_promotion.png +0 -0
  101. package/test/references/{11_chessboard_play_promotions → 12_chessboard_play_promotions}/cancel_promotion.png +0 -0
  102. package/test/references/{11_chessboard_play_promotions → 12_chessboard_play_promotions}/regular_promotion_1.png +0 -0
  103. package/test/references/{11_chessboard_play_promotions → 12_chessboard_play_promotions}/regular_promotion_2.png +0 -0
  104. package/test/references/{12_movetext_simple → 13_movetext_simple}/0.png +0 -0
  105. package/test/references/{12_movetext_simple → 13_movetext_simple}/1.png +0 -0
  106. package/test/references/{12_movetext_simple → 13_movetext_simple}/2.png +0 -0
  107. package/test/references/{12_movetext_simple → 13_movetext_simple}/3.png +0 -0
  108. package/test/references/14_movetext_error/0.png +0 -0
  109. package/test/references/14_movetext_error/1.png +0 -0
  110. package/test/references/{13_movetext_error/1.png → 14_movetext_error/2.png} +0 -0
  111. package/test/references/14_movetext_error/3.png +0 -0
  112. package/test/references/14_movetext_error/4.png +0 -0
  113. package/test/references/15_movetext_html/0.png +0 -0
  114. package/test/references/15_movetext_html/1.png +0 -0
  115. package/test/references/{14_movetext_html → 15_movetext_html}/2.png +0 -0
  116. package/test/references/{15_movetext_options → 16_movetext_options}/0.png +0 -0
  117. package/test/references/{15_movetext_options → 16_movetext_options}/1.png +0 -0
  118. package/test/references/{15_movetext_options → 16_movetext_options}/2.png +0 -0
  119. package/test/references/{15_movetext_options → 16_movetext_options}/3.png +0 -0
  120. package/test/references/{16_movetext_interaction → 17_movetext_interaction}/0.png +0 -0
  121. package/test/references/{16_movetext_interaction → 17_movetext_interaction}/1.png +0 -0
  122. package/test/references/{16_movetext_interaction → 17_movetext_interaction}/2.png +0 -0
  123. package/CHANGELOG.md +0 -131
  124. package/graphics/chess_sprites/cburnett/bb.svg +0 -45
  125. package/graphics/chess_sprites/cburnett/bk.svg +0 -47
  126. package/graphics/chess_sprites/cburnett/bn.svg +0 -37
  127. package/graphics/chess_sprites/cburnett/bp.svg +0 -19
  128. package/graphics/chess_sprites/cburnett/bq.svg +0 -58
  129. package/graphics/chess_sprites/cburnett/br.svg +0 -60
  130. package/graphics/chess_sprites/cburnett/bx.svg +0 -56
  131. package/graphics/chess_sprites/cburnett/wb.svg +0 -48
  132. package/graphics/chess_sprites/cburnett/wk.svg +0 -26
  133. package/graphics/chess_sprites/cburnett/wn.svg +0 -37
  134. package/graphics/chess_sprites/cburnett/wp.svg +0 -19
  135. package/graphics/chess_sprites/cburnett/wq.svg +0 -60
  136. package/graphics/chess_sprites/cburnett/wr.svg +0 -44
  137. package/graphics/chess_sprites/cburnett/wx.svg +0 -56
  138. package/graphics/chess_sprites/generate_sprites.sh +0 -135
  139. package/graphics/chess_sprites/mmonge/celtic-bx.svg +0 -112
  140. package/graphics/chess_sprites/mmonge/celtic-wx.svg +0 -111
  141. package/graphics/chess_sprites/mmonge/celtic.svg +0 -1576
  142. package/graphics/chess_sprites/mmonge/eyes-spatial-bx.svg +0 -101
  143. package/graphics/chess_sprites/mmonge/eyes-spatial-wx.svg +0 -100
  144. package/graphics/chess_sprites/mmonge/eyes.svg +0 -2538
  145. package/graphics/chess_sprites/mmonge/fantasy-bx.svg +0 -112
  146. package/graphics/chess_sprites/mmonge/fantasy-wx.svg +0 -111
  147. package/graphics/chess_sprites/mmonge/fantasy.svg +0 -5497
  148. package/graphics/chess_sprites/mmonge/fantasy_alt.svg +0 -3742
  149. package/graphics/chess_sprites/mmonge/freak.svg +0 -3479
  150. package/graphics/chess_sprites/mmonge/prmi.svg +0 -6776
  151. package/graphics/chess_sprites/mmonge/skulls-bx.svg +0 -124
  152. package/graphics/chess_sprites/mmonge/skulls-wx.svg +0 -111
  153. package/graphics/chess_sprites/mmonge/skulls.svg +0 -12978
  154. package/graphics/chess_sprites/mmonge/spatial.svg +0 -1223
  155. package/graphics/logo-small.svg +0 -14
  156. package/graphics/logo.svg +0 -26
  157. package/test/references/13_movetext_error/0.png +0 -0
  158. package/test/references/13_movetext_error/2.png +0 -0
  159. package/test/references/13_movetext_error/3.png +0 -0
  160. package/test/references/14_movetext_html/0.png +0 -0
  161. 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 { Motion, spring } from 'react-motion';
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 ANIMATION_SPEED = { stiffness: 700, damping: 40 };
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
- window.removeEventListener('resize', this.windowResizeListener);
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
- kokopu.forEachSquare(sq => squares.push(this.renderSquare(squareSize, colorset, sq)));
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={move.toString()} defaultStyle={{ alpha: 0 }} style={{ alpha: spring(1, ANIMATION_SPEED) }}>
143
- {currentStyle => (currentStyle.alpha >= 1 ? this.renderBoardContentStill(position, move, squareSize, colorset, pieceset)
144
- : this.renderBoardContentAnimated(positionBefore, move, currentStyle.alpha, squareSize, colorset, pieceset))}
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, alpha, squareSize, colorset, pieceset) {
160
+ renderBoardContentAnimated(positionBefore, move, motionCursor, squareSize, colorset, pieceset) {
157
161
  let pieces = [];
158
- kokopu.forEachSquare(sq => pieces.push(this.renderPieceAnimated(positionBefore, move, alpha, squareSize, pieceset, sq)));
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, alpha, squareSize, colorset)}
163
- {this.renderTurnFlag(kokopu.oppositeColor(positionBefore.turn()), squareSize, pieceset)}
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
- kokopu.forEachSquare(sq => {
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[kokopu.squareColor(sq)]} />;
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, alpha, squareSize, pieceset, sq) {
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 * alpha + x * (1 - alpha);
238
- y = yTo * alpha + y * (1 - alpha);
239
- if (move.isPromotion() && alpha > 0.8) {
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 * alpha + x * (1 - alpha);
246
- y = yTo * alpha + y * (1 - alpha);
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, alpha, squareSize, colorset) {
388
- if (!move || alpha < 0.1 || !this.props.moveArrowVisible || move.from() === move.to()) {
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 * alpha + xFrom * (1 - alpha);
400
- let y = yTo * alpha + yFrom * (1 - alpha);
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 } = kokopu.squareToCoordinates(sq);
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 kokopu.Position(positionInfo.position);
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 ? kokopu.coordinatesToSquare(file, rank) : '-';
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/global.html#GameVariant) supported by Kokopu. For instance:
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(kokopu.Position),
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
- function(props, propName, componentName) {
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 kokopu.Position) {
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 kokopu.Position(position) };
969
+ return { error: false, position: new Position(position) };
970
970
  }
971
971
  catch (e) {
972
972
  // istanbul ignore else
973
- if (e instanceof kokopu.exception.InvalidFEN) {
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 (kokopu.isMoveDescriptor(move)) {
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 kokopu.exception.InvalidNotation) {
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 += ' (' + i18n.LINE.replace(/\{0\}/g, lineNumber) + ')';
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 kokopu from 'kokopu';
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">{sanitizeHtml(rating)}</span>;
89
+ let ratingElement = rating === undefined ? undefined : <span className="kokopu-header-playerRating">{rating}</span>;
89
90
  let separator = title === undefined || rating === undefined ? undefined : '\u00a0'; // \u00a0 == &nbsp;
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.replace(/\{0\}/g, annotator);
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}>{kokopu.nagSymbol(nag)}</span>);
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(kokopu.Game),
491
- PropTypes.instanceOf(kokopu.Database),
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 kokopu.Game(),
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 kokopu.Game) {
647
+ if (game instanceof Game) {
647
648
  return { error: false, game: game };
648
649
  }
649
- else if (game instanceof kokopu.Database || typeof game === 'string') {
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
- let result = game instanceof kokopu.Database ? game.game(gameIndex) : kokopu.pgnRead(game, gameIndex);
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 kokopu.exception.InvalidPGN) {
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;
@@ -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" fill={props.color}>
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, '06_chessboard_theme', [ 'default', 'large', 'small', 'custom 1', 'custom 2', 'custom 3',
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, '07_chessboard_click_squares', itemIndex, label, async function(element) {
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, '08_chessboard_move_pieces', itemIndex, label, async function(element) {
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, '08_chessboard_move_pieces', itemIndex, label, async function(element) {
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, '09_chessboard_edit_arrows', itemIndex, label, async function(element) {
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, '09_chessboard_edit_arrows', itemIndex, label, async function(element) {
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, '10_chessboard_play_moves', itemIndex, label, async function(element) {
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, '10_chessboard_play_moves', itemIndex, label, async function(element) {
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, '11_chessboard_play_promotions', itemIndex, label, async function(element) {
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, '11_chessboard_play_promotions', itemIndex, label, async function(element) {
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, '12_movetext_simple', [ 'game-0', 'game-1', 'game-2', 'game-3' ]);
39
- itChecksScreenshots(browserContext, '13_movetext_error', [ 'wrong-game-index', 'pgn-parsing-error-1', 'pgn-parsing-error-2', 'wrong type' ]);
40
- itChecksScreenshots(browserContext, '14_movetext_html', [ 'html-in-headers', 'html-in-comments', 'filtered-tags-and-attributes' ]);
41
- itChecksScreenshots(browserContext, '15_movetext_options', [ 'localized-piece-symbols', 'custom-piece-symbols', 'figurine-piece-symbols-and-diagram-options',
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, '16_movetext_interaction', itemIndex, label, async function(element) {
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, '16_movetext_interaction', itemIndex, label, async function(element) {
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, '');