@alepot55/chessboardjs 2.1.7 → 2.2.1

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/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # Chessboard.js: Interactive and Customizable Chessboard Library
2
2
 
3
- Chessboard.js is a lightweight and versatile NPM package that lets you easily integrate an interactive, customizable chessboard into your web applications. Use it for game displays, chess lessons, analysis tools, or any project that needs a visual chess interface.
3
+ [Chessboard.js](https://sites.google.com/view/chessboard-js/home) is a lightweight and versatile NPM package that lets you easily integrate an interactive, customizable chessboard into your web applications. Use it for game displays, chess lessons, analysis tools, or any project that needs a visual chess interface.
4
4
 
5
5
  ## Overview
6
- Chessboard.js is designed with simplicity and flexibility in mind. Configure board appearance, piece sets, orientation, highlighting, animations, and more through a rich API. The board updates dynamically with user interactions and programmatic moves.
6
+ [Chessboard.js](https://sites.google.com/view/chessboard-js/home) is designed with simplicity and flexibility in mind. Configure board appearance, piece sets, orientation, highlighting, animations, and more through a rich API. The board updates dynamically with user interactions and programmatic moves.
7
7
 
8
8
  ## Installation
9
9
  ```bash
@@ -384,7 +384,7 @@ This document details the functions available to users for interacting with the
384
384
  Places a piece on the board.
385
385
  _Example:_
386
386
  ```js
387
- board.put({ type: 'p', color: 'w' }, 'd4');
387
+ board.put('pw', 'd4');
388
388
  ```
389
389
 
390
390
  - **remove(squareId, animation = true)**
@@ -1997,7 +1997,8 @@ var Chessboard = (function () {
1997
1997
  'linear': 'linear',
1998
1998
  'ease-in': 'ease-in',
1999
1999
  'ease-out': 'ease-out',
2000
- 'ease-in-out': 'ease-in-out'
2000
+ 'ease-in-out': 'ease-in-out',
2001
+ 'none': null
2001
2002
  };
2002
2003
 
2003
2004
  class ChessboardConfig {
@@ -2051,9 +2052,6 @@ var Chessboard = (function () {
2051
2052
  this.dropOffBoard = config.dropOffBoard;
2052
2053
  this.size = config.size;
2053
2054
  this.movableColors = config.movableColors;
2054
- this.moveAnimation = config.moveAnimation;
2055
- this.snapbackAnimation = config.snapbackAnimation;
2056
- this.fadeAnimation = config.fadeAnimation;
2057
2055
  this.piecesPath = config.piecesPath;
2058
2056
  this.onMove = config.onMove;
2059
2057
  this.onMoveEnd = config.onMoveEnd;
@@ -2063,6 +2061,10 @@ var Chessboard = (function () {
2063
2061
  this.onDrop = config.onDrop;
2064
2062
  this.onSnapbackEnd = config.onSnapbackEnd;
2065
2063
 
2064
+ this.moveAnimation = this.setTransitionFunction(config.moveAnimation);
2065
+ this.snapbackAnimation = this.setTransitionFunction(config.snapbackAnimation);
2066
+ this.fadeAnimation = this.setTransitionFunction(config.fadeAnimation);
2067
+
2066
2068
  this.hints = this.setBoolean(config.hints);
2067
2069
  this.clickable = this.setBoolean(config.clickable);
2068
2070
  this.draggable = this.setBoolean(config.draggable);
@@ -2115,7 +2117,7 @@ var Chessboard = (function () {
2115
2117
  }
2116
2118
 
2117
2119
  setTransitionFunction(value) {
2118
- if (transitionFunctions[value]) return transitionFunctions[value];
2120
+ if (Object.keys(transitionFunctions).indexOf(value) !== -1) return transitionFunctions[value];
2119
2121
  throw new Error('Invalid transition function');
2120
2122
  }
2121
2123
  }
@@ -2168,7 +2170,7 @@ var Chessboard = (function () {
2168
2170
  }
2169
2171
 
2170
2172
  setDrag(f) {
2171
- this.element.ondragstart = () => false;
2173
+ this.element.ondragstart = (e) => { e.preventDefault(); };
2172
2174
  this.element.onmousedown = f;
2173
2175
  }
2174
2176
 
@@ -2423,27 +2425,15 @@ var Chessboard = (function () {
2423
2425
  }
2424
2426
 
2425
2427
  check() {
2426
- if (this.piece === null) {
2427
- throw new Error("Invalid move: piece is null");
2428
- }
2429
- if (!(this.piece instanceof Piece)) {
2430
- throw new Error("Invalid move: piece is not an instance of Piece");
2431
- }
2432
- if (['q', 'r', 'b', 'n', null].indexOf(this.promotion) === -1) {
2433
- throw new Error("Invalid move: promotion is not valid");
2434
- }
2435
- if (!(this.from instanceof Square)) {
2436
- throw new Error("Invalid move: from is not an instance of Square");
2437
- }
2438
- if (!(this.to instanceof Square)) {
2439
- throw new Error("Invalid move: to is not an instance of Square");
2440
- }
2441
- if (!this.to) {
2442
- throw new Error("Invalid move: to is null or undefined");
2443
- }
2444
- if (!this.from) {
2445
- throw new Error("Invalid move: from is null or undefined");
2446
- }
2428
+ if (this.piece === null) return false;
2429
+ if (!(this.piece instanceof Piece)) return false;
2430
+ if (['q', 'r', 'b', 'n', null].indexOf(this.promotion) === -1) return false;
2431
+ if (!(this.from instanceof Square)) return false;
2432
+ if (!(this.to instanceof Square)) return false;
2433
+ if (!this.to) return false;
2434
+ if (!this.from) return false;
2435
+ if (this.from === this.to) return false;
2436
+ return true;
2447
2437
  }
2448
2438
 
2449
2439
  isLegal(game) {
@@ -2515,7 +2505,7 @@ var Chessboard = (function () {
2515
2505
  }
2516
2506
 
2517
2507
  initParams() {
2518
- this.board = null;
2508
+ this.element = null;
2519
2509
  this.squares = {};
2520
2510
  this.promoting = false;
2521
2511
  this.clicked = null;
@@ -2527,12 +2517,12 @@ var Chessboard = (function () {
2527
2517
  // Board Setup
2528
2518
  // -------------------
2529
2519
  buildBoard() {
2530
- this.board = document.getElementById(this.config.id_div);
2531
- if (!this.board) {
2520
+ this.element = document.getElementById(this.config.id_div);
2521
+ if (!this.element) {
2532
2522
  throw new Error(this.error_messages['invalid_id_div'] + this.config.id_div);
2533
2523
  }
2534
2524
  this.resize(this.config.size);
2535
- this.board.className = "board";
2525
+ this.element.className = "board";
2536
2526
  }
2537
2527
 
2538
2528
  buildSquares() {
@@ -2544,19 +2534,19 @@ var Chessboard = (function () {
2544
2534
  let square = new Square(square_row, square_col);
2545
2535
  this.squares[square.getId()] = square;
2546
2536
 
2547
- this.board.appendChild(square.element);
2537
+ this.element.appendChild(square.element);
2548
2538
  }
2549
2539
  }
2550
2540
  }
2551
2541
 
2552
2542
  removeBoard() {
2553
2543
 
2554
- this.board.innerHTML = '';
2544
+ this.element.innerHTML = '';
2555
2545
  }
2556
2546
 
2557
2547
  removeSquares() {
2558
2548
  for (const square of Object.values(this.squares)) {
2559
- this.board.removeChild(square.element);
2549
+ this.element.removeChild(square.element);
2560
2550
  square.destroy();
2561
2551
 
2562
2552
  }
@@ -2566,12 +2556,12 @@ var Chessboard = (function () {
2566
2556
  resize(value) {
2567
2557
  if (value === 'auto') {
2568
2558
  let size;
2569
- if (this.board.offsetWidth === 0) {
2570
- size = this.board.offsetHeight;
2571
- } else if (this.board.offsetHeight === 0) {
2572
- size = this.board.offsetWidth;
2559
+ if (this.element.offsetWidth === 0) {
2560
+ size = this.element.offsetHeight;
2561
+ } else if (this.element.offsetHeight === 0) {
2562
+ size = this.element.offsetWidth;
2573
2563
  } else {
2574
- size = Math.min(this.board.offsetWidth, this.board.offsetHeight);
2564
+ size = Math.min(this.element.offsetWidth, this.element.offsetHeight);
2575
2565
  }
2576
2566
  this.resize(size);
2577
2567
  } else if (typeof value !== 'number') {
@@ -2587,6 +2577,7 @@ var Chessboard = (function () {
2587
2577
  // -------------------
2588
2578
  convertFen(position) {
2589
2579
  if (typeof position === 'string') {
2580
+ if (position == 'start') return 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
2590
2581
  if (this.validateFen(position)) return position;
2591
2582
  else if (this.standard_positions[position]) return this.standard_positions[position];
2592
2583
  else throw new Error('Invalid position -' + position);
@@ -2613,15 +2604,15 @@ var Chessboard = (function () {
2613
2604
  if (empty > 0) rowParts.push(empty);
2614
2605
  parts.push(rowParts.join(''));
2615
2606
  }
2616
- return parts.join('/');
2617
- } else {
2607
+ return parts.join('/') + ' w KQkq - 0 1'; } else {
2618
2608
  throw new Error('Invalid position -' + position);
2619
2609
  }
2620
2610
  }
2621
2611
 
2622
- setGame(position) {
2612
+ setGame(position, options = undefined) {
2623
2613
  const fen = this.convertFen(position);
2624
- this.game = new Chess(fen);
2614
+ if (this.game) this.game.load(fen, options);
2615
+ else this.game = new Chess(fen);
2625
2616
  }
2626
2617
 
2627
2618
  // -------------------
@@ -2701,7 +2692,7 @@ var Chessboard = (function () {
2701
2692
 
2702
2693
  }
2703
2694
 
2704
- snapbackPiece(square, animate) {
2695
+ snapbackPiece(square, animate = this.config.snapbackAnimation) {
2705
2696
  let move = new Move(square, square);
2706
2697
  this.translatePiece(move, false, animate);
2707
2698
  }
@@ -2712,11 +2703,15 @@ var Chessboard = (function () {
2712
2703
  updateBoardPieces(animation = false) {
2713
2704
  let { updatedFlags, escapeFlags, movableFlags, pendingTranslations } = this.prepareBoardUpdateData();
2714
2705
 
2706
+ let change = Object.values(updatedFlags).some(flag => !flag);
2707
+
2715
2708
  this.identifyPieceTranslations(updatedFlags, escapeFlags, movableFlags, pendingTranslations);
2716
2709
 
2717
2710
  this.executePieceTranslations(pendingTranslations, escapeFlags, animation);
2718
2711
 
2719
2712
  this.processRemainingPieceUpdates(updatedFlags, animation);
2713
+
2714
+ if (change) this.config.onChange(this.fen());
2720
2715
  }
2721
2716
 
2722
2717
  prepareBoardUpdateData() {
@@ -2816,11 +2811,9 @@ var Chessboard = (function () {
2816
2811
  updateSinglePiece(square, newPiece, updatedFlags, animation) {
2817
2812
  if (!updatedFlags[square.id]) {
2818
2813
  let lastMove = this.lastMove();
2819
- console.log(lastMove);
2820
2814
 
2821
2815
  if (lastMove?.promotion) {
2822
2816
  if (lastMove['to'] === square.id) {
2823
- console.log('Promotion detected');
2824
2817
 
2825
2818
  let move = new Move(this.squares[lastMove['from']], square);
2826
2819
  this.translatePiece(move, true, animation
@@ -2846,7 +2839,6 @@ var Chessboard = (function () {
2846
2839
  event.preventDefault();
2847
2840
 
2848
2841
  if (!this.config.draggable || !piece) return;
2849
- if (!this.config.onDragStart(square, piece)) return;
2850
2842
 
2851
2843
  let prec;
2852
2844
  let from = square;
@@ -2856,7 +2848,7 @@ var Chessboard = (function () {
2856
2848
 
2857
2849
  if (!this.canMove(from)) return;
2858
2850
  if (!this.config.clickable) this.clicked = null;
2859
- if (this.onClick(from)) return;
2851
+ if (this.onClick(from, true, true)) return;
2860
2852
 
2861
2853
  img.style.position = 'absolute';
2862
2854
  img.style.zIndex = 100;
@@ -2870,10 +2862,11 @@ var Chessboard = (function () {
2870
2862
  };
2871
2863
 
2872
2864
  const onMouseMove = (event) => {
2865
+ if (!this.config.onDragStart(square, piece)) return;
2873
2866
  if (!moveAt(event.pageX, event.pageY)) ;
2874
2867
 
2875
- const boardRect = this.board.getBoundingClientRect();
2876
- const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.board;
2868
+ const boardRect = this.element.getBoundingClientRect();
2869
+ const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.element;
2877
2870
  const x = event.clientX - boardRect.left;
2878
2871
  const y = event.clientY - boardRect.top;
2879
2872
 
@@ -2908,9 +2901,9 @@ var Chessboard = (function () {
2908
2901
  this.allSquares('removeHint');
2909
2902
  from.deselect();
2910
2903
  this.remove(from);
2911
- } else if (!to || !this.onClick(to, true)) {
2912
- this.snapbackPiece(from, !this.promoting);
2913
- this.config.onSnapbackEnd(from, piece);
2904
+ } else if (!to || !this.onClick(to, true, true)) {
2905
+ this.snapbackPiece(from);
2906
+ if (to !== from) this.config.onSnapbackEnd(from, piece);
2914
2907
  }
2915
2908
  };
2916
2909
 
@@ -2937,14 +2930,14 @@ var Chessboard = (function () {
2937
2930
  if (this.config.clickable && (!piece || this.config.onlyLegalMoves)) this.onClick(square);
2938
2931
  };
2939
2932
 
2940
- square.element.addEventListener("click", handleClick);
2933
+ square.element.addEventListener("mousedown", handleClick);
2941
2934
  square.element.addEventListener("touch", handleClick);
2942
2935
  }
2943
2936
  }
2944
2937
 
2945
- onClick(square, animation = this.config.moveAnimation) {
2946
-
2947
- if (square.id === this.clicked?.id) return false;
2938
+ onClick(square, animation = this.config.moveAnimation, dragged = false) {
2939
+
2940
+ if (this.clicked === square) return false;
2948
2941
 
2949
2942
  let from = this.clicked;
2950
2943
  this.clicked = null;
@@ -2963,19 +2956,22 @@ var Chessboard = (function () {
2963
2956
  if (!from) {
2964
2957
 
2965
2958
  if (this.canMove(square)) {
2966
- square.select();
2967
- this.hintMoves(square);
2959
+ if (this.config.clickable) {
2960
+ square.select();
2961
+ this.hintMoves(square);
2962
+ }
2968
2963
  this.clicked = square;
2969
2964
  }
2970
2965
 
2971
2966
  return false;
2972
2967
  }
2973
2968
 
2974
- if (!this.canMove(from)) return false;
2975
-
2976
2969
  let move = new Move(from, square, promotion);
2977
2970
 
2978
2971
  move.from.deselect();
2972
+
2973
+ if (!move.check()) return false;
2974
+
2979
2975
  this.allSquares("removeHint");
2980
2976
 
2981
2977
  if (this.config.onlyLegalMoves && !move.isLegal(this.game)) return false;
@@ -3030,7 +3026,7 @@ var Chessboard = (function () {
3030
3026
  return this.game.moves({ verbose: verb });
3031
3027
  }
3032
3028
 
3033
- move(move, animation) {
3029
+ move(move, animation = true) {
3034
3030
  move = this.convertMove(move);
3035
3031
  move.check();
3036
3032
 
@@ -3201,36 +3197,60 @@ var Chessboard = (function () {
3201
3197
  }
3202
3198
 
3203
3199
  setOrientation(color, animation = true) {
3204
- if (!['w', 'b'].includes(color)) {
3205
- this.config.orientation = color;
3206
- this.flip(animation);
3200
+ if (['w', 'b'].includes(color)) {
3201
+ if (color !== this.config.orientation) {
3202
+ this.flip(animation);
3203
+ }
3207
3204
  } else {
3208
3205
  throw new Error(this.error_messages['invalid_orientation'] + color);
3209
3206
  }
3210
3207
  }
3211
3208
 
3209
+ highlight(squareId) {
3210
+ let square = this.convertSquare(squareId);
3211
+ square.check();
3212
+ square.highlight();
3213
+ }
3214
+
3215
+ dehighlight(squareId) {
3216
+ let square = this.convertSquare(squareId);
3217
+ square.check();
3218
+ square.dehighlight();
3219
+ }
3220
+
3212
3221
  lastMove() {
3213
3222
  const moves = this.history({ verbose: true });
3214
3223
  return moves[moves.length - 1];
3215
3224
  }
3216
3225
 
3217
- flip(animation = true) {
3218
- this.clearSquares();
3219
- this.allSquares('opposite');
3220
- this.updateBoardPieces(animation);
3226
+ flip() {
3227
+ this.config.orientation = this.config.orientation === 'w' ? 'b' : 'w';
3228
+ this.destroy();
3229
+ this.initParams();
3230
+ this.build();
3221
3231
  }
3222
3232
 
3223
3233
  build() {
3224
- if (this.board) throw new Error('Board already built');
3234
+ if (this.element) this.destroy();
3225
3235
  this.init();
3226
3236
  }
3227
3237
 
3238
+ destroy() {
3239
+ this.removeSquares();
3240
+ this.removeBoard();
3241
+ }
3242
+
3228
3243
  ascii() {
3229
3244
  return this.game.ascii();
3230
3245
  }
3231
3246
 
3232
3247
  board() {
3233
- return this.game.board();
3248
+ let dict = {};
3249
+ for (let squareId in this.squares) {
3250
+ let piece = this.getGamePieceId(squareId);
3251
+ if (piece) dict[squareId] = piece;
3252
+ }
3253
+ return dict;
3234
3254
  }
3235
3255
 
3236
3256
  clear(options = {}, animation = true) {
@@ -3245,7 +3265,7 @@ var Chessboard = (function () {
3245
3265
  get(squareId) {
3246
3266
  const square = this.convertSquare(squareId);
3247
3267
  square.check();
3248
- return square.piece;
3268
+ return square.piece;
3249
3269
  }
3250
3270
 
3251
3271
  getCastlingRights(color) {
@@ -3292,9 +3312,9 @@ var Chessboard = (function () {
3292
3312
  return this.game.isThreefoldRepetition();
3293
3313
  }
3294
3314
 
3295
- load(fen, options = {}, animation = true) {
3315
+ load(position, options = {}, animation = true) {
3296
3316
  this.clearSquares();
3297
- this.game.load(fen, options);
3317
+ this.setGame(position, options);
3298
3318
  this.updateBoardPieces(animation);
3299
3319
  }
3300
3320
 
@@ -3317,7 +3337,8 @@ var Chessboard = (function () {
3317
3337
  }
3318
3338
 
3319
3339
  put(pieceId, squareId, animation = true) {
3320
- const success = this.game.put(pieceId, squareId);
3340
+ const [type, color] = pieceId.split('');
3341
+ const success = this.game.put({ type: type, color: color }, squareId);
3321
3342
  if (success) this.updateBoardPieces(animation);
3322
3343
  return success;
3323
3344
  }
@@ -3356,7 +3377,7 @@ var Chessboard = (function () {
3356
3377
  setHeader(key, value) {
3357
3378
  return this.game.setHeader(key, value);
3358
3379
  }
3359
-
3380
+
3360
3381
  squareColor(squareId) {
3361
3382
  return this.game.squareColor(squareId);
3362
3383
  }
@@ -3397,4 +3418,5 @@ var Chessboard = (function () {
3397
3418
  return Chessboard;
3398
3419
 
3399
3420
  })();
3400
- window.Chessboard.Chessboard = Chessboard;
3421
+
3422
+ window.Chessboard.Chessboard = Chessboard;
@@ -19,7 +19,8 @@ const transitionFunctions = {
19
19
  'linear': 'linear',
20
20
  'ease-in': 'ease-in',
21
21
  'ease-out': 'ease-out',
22
- 'ease-in-out': 'ease-in-out'
22
+ 'ease-in-out': 'ease-in-out',
23
+ 'none': null
23
24
  };
24
25
 
25
26
  class ChessboardConfig {
@@ -73,9 +74,6 @@ class ChessboardConfig {
73
74
  this.dropOffBoard = config.dropOffBoard;
74
75
  this.size = config.size;
75
76
  this.movableColors = config.movableColors;
76
- this.moveAnimation = config.moveAnimation;
77
- this.snapbackAnimation = config.snapbackAnimation;
78
- this.fadeAnimation = config.fadeAnimation;
79
77
  this.piecesPath = config.piecesPath;
80
78
  this.onMove = config.onMove;
81
79
  this.onMoveEnd = config.onMoveEnd;
@@ -85,6 +83,10 @@ class ChessboardConfig {
85
83
  this.onDrop = config.onDrop;
86
84
  this.onSnapbackEnd = config.onSnapbackEnd;
87
85
 
86
+ this.moveAnimation = this.setTransitionFunction(config.moveAnimation);
87
+ this.snapbackAnimation = this.setTransitionFunction(config.snapbackAnimation);
88
+ this.fadeAnimation = this.setTransitionFunction(config.fadeAnimation);
89
+
88
90
  this.hints = this.setBoolean(config.hints);
89
91
  this.clickable = this.setBoolean(config.clickable);
90
92
  this.draggable = this.setBoolean(config.draggable);
@@ -137,7 +139,7 @@ class ChessboardConfig {
137
139
  }
138
140
 
139
141
  setTransitionFunction(value) {
140
- if (transitionFunctions[value]) return transitionFunctions[value];
142
+ if (Object.keys(transitionFunctions).indexOf(value) !== -1) return transitionFunctions[value];
141
143
  throw new Error('Invalid transition function');
142
144
  }
143
145
  }
package/chessboard.js CHANGED
@@ -65,7 +65,7 @@ class Chessboard {
65
65
  }
66
66
 
67
67
  initParams() {
68
- this.board = null;
68
+ this.element = null;
69
69
  this.squares = {};
70
70
  this.promoting = false;
71
71
  this.clicked = null;
@@ -77,12 +77,12 @@ class Chessboard {
77
77
  // Board Setup
78
78
  // -------------------
79
79
  buildBoard() {
80
- this.board = document.getElementById(this.config.id_div);
81
- if (!this.board) {
80
+ this.element = document.getElementById(this.config.id_div);
81
+ if (!this.element) {
82
82
  throw new Error(this.error_messages['invalid_id_div'] + this.config.id_div);
83
83
  }
84
84
  this.resize(this.config.size);
85
- this.board.className = "board";
85
+ this.element.className = "board";
86
86
  }
87
87
 
88
88
  buildSquares() {
@@ -94,19 +94,19 @@ class Chessboard {
94
94
  let square = new Square(square_row, square_col);
95
95
  this.squares[square.getId()] = square;
96
96
 
97
- this.board.appendChild(square.element);
97
+ this.element.appendChild(square.element);
98
98
  }
99
99
  }
100
100
  }
101
101
 
102
102
  removeBoard() {
103
103
 
104
- this.board.innerHTML = '';
104
+ this.element.innerHTML = '';
105
105
  }
106
106
 
107
107
  removeSquares() {
108
108
  for (const square of Object.values(this.squares)) {
109
- this.board.removeChild(square.element);
109
+ this.element.removeChild(square.element);
110
110
  square.destroy();
111
111
 
112
112
  }
@@ -116,12 +116,12 @@ class Chessboard {
116
116
  resize(value) {
117
117
  if (value === 'auto') {
118
118
  let size;
119
- if (this.board.offsetWidth === 0) {
120
- size = this.board.offsetHeight;
121
- } else if (this.board.offsetHeight === 0) {
122
- size = this.board.offsetWidth;
119
+ if (this.element.offsetWidth === 0) {
120
+ size = this.element.offsetHeight;
121
+ } else if (this.element.offsetHeight === 0) {
122
+ size = this.element.offsetWidth;
123
123
  } else {
124
- size = Math.min(this.board.offsetWidth, this.board.offsetHeight);
124
+ size = Math.min(this.element.offsetWidth, this.element.offsetHeight);
125
125
  }
126
126
  this.resize(size);
127
127
  } else if (typeof value !== 'number') {
@@ -137,7 +137,7 @@ class Chessboard {
137
137
  // -------------------
138
138
  convertFen(position) {
139
139
  if (typeof position === 'string') {
140
-
140
+ if (position == 'start') return 'rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1';
141
141
  if (this.validateFen(position)) return position;
142
142
  else if (this.standard_positions[position]) return this.standard_positions[position];
143
143
  else throw new Error('Invalid position -' + position);
@@ -164,15 +164,16 @@ class Chessboard {
164
164
  if (empty > 0) rowParts.push(empty);
165
165
  parts.push(rowParts.join(''));
166
166
  }
167
- return parts.join('/');
167
+ return parts.join('/') + ' w KQkq - 0 1';;
168
168
  } else {
169
169
  throw new Error('Invalid position -' + position);
170
170
  }
171
171
  }
172
172
 
173
- setGame(position) {
173
+ setGame(position, options = undefined) {
174
174
  const fen = this.convertFen(position);
175
- this.game = new Chess(fen === 'start' ? this.standard_positions['default'] : null);
175
+ if (this.game) this.game.load(fen, options);
176
+ else this.game = new Chess(fen);
176
177
  }
177
178
 
178
179
  // -------------------
@@ -252,7 +253,7 @@ class Chessboard {
252
253
 
253
254
  }
254
255
 
255
- snapbackPiece(square, animate) {
256
+ snapbackPiece(square, animate = this.config.snapbackAnimation) {
256
257
  let move = new Move(square, square);
257
258
  this.translatePiece(move, false, animate);
258
259
  }
@@ -263,11 +264,15 @@ class Chessboard {
263
264
  updateBoardPieces(animation = false) {
264
265
  let { updatedFlags, escapeFlags, movableFlags, pendingTranslations } = this.prepareBoardUpdateData();
265
266
 
267
+ let change = Object.values(updatedFlags).some(flag => !flag);
268
+
266
269
  this.identifyPieceTranslations(updatedFlags, escapeFlags, movableFlags, pendingTranslations);
267
270
 
268
271
  this.executePieceTranslations(pendingTranslations, escapeFlags, animation);
269
272
 
270
273
  this.processRemainingPieceUpdates(updatedFlags, animation);
274
+
275
+ if (change) this.config.onChange(this.fen());
271
276
  }
272
277
 
273
278
  prepareBoardUpdateData() {
@@ -395,9 +400,8 @@ class Chessboard {
395
400
  event.preventDefault();
396
401
 
397
402
  if (!this.config.draggable || !piece) return;
398
- if (!this.config.onDragStart(square, piece)) return;
399
403
 
400
- let prec;
404
+ let prec, moved;
401
405
  let from = square;
402
406
  let to = square;
403
407
 
@@ -405,7 +409,7 @@ class Chessboard {
405
409
 
406
410
  if (!this.canMove(from)) return;
407
411
  if (!this.config.clickable) this.clicked = null;
408
- if (this.onClick(from)) return;
412
+ if (this.onClick(from, true, true)) return;
409
413
 
410
414
  img.style.position = 'absolute';
411
415
  img.style.zIndex = 100;
@@ -419,10 +423,11 @@ class Chessboard {
419
423
  };
420
424
 
421
425
  const onMouseMove = (event) => {
426
+ if (!this.config.onDragStart(square, piece)) return;
422
427
  if (!moveAt(event.pageX, event.pageY)) return;
423
428
 
424
- const boardRect = this.board.getBoundingClientRect();
425
- const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.board;
429
+ const boardRect = this.element.getBoundingClientRect();
430
+ const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.element;
426
431
  const x = event.clientX - boardRect.left;
427
432
  const y = event.clientY - boardRect.top;
428
433
 
@@ -457,9 +462,9 @@ class Chessboard {
457
462
  this.allSquares('removeHint');
458
463
  from.deselect();
459
464
  this.remove(from);
460
- } else if (!to || !this.onClick(to, true)) {
461
- this.snapbackPiece(from, !this.promoting);
462
- this.config.onSnapbackEnd(from, piece);
465
+ } else if (!to || !this.onClick(to, true, true)) {
466
+ this.snapbackPiece(from);
467
+ if (to !== from) this.config.onSnapbackEnd(from, piece);
463
468
  }
464
469
  };
465
470
 
@@ -486,14 +491,14 @@ class Chessboard {
486
491
  if (this.config.clickable && (!piece || this.config.onlyLegalMoves)) this.onClick(square)
487
492
  }
488
493
 
489
- square.element.addEventListener("click", handleClick);
494
+ square.element.addEventListener("mousedown", handleClick);
490
495
  square.element.addEventListener("touch", handleClick);
491
496
  }
492
497
  }
493
498
 
494
- onClick(square, animation = this.config.moveAnimation) {
495
-
496
- if (square.id === this.clicked?.id) return false;
499
+ onClick(square, animation = this.config.moveAnimation, dragged = false) {
500
+
501
+ if (this.clicked === square) return false;
497
502
 
498
503
  let from = this.clicked;
499
504
  this.clicked = null;
@@ -512,19 +517,22 @@ class Chessboard {
512
517
  if (!from) {
513
518
 
514
519
  if (this.canMove(square)) {
515
- square.select();
516
- this.hintMoves(square);
520
+ if (this.config.clickable) {
521
+ square.select();
522
+ this.hintMoves(square);
523
+ }
517
524
  this.clicked = square;
518
525
  }
519
526
 
520
527
  return false;
521
528
  }
522
529
 
523
- if (!this.canMove(from)) return false;
524
-
525
530
  let move = new Move(from, square, promotion);
526
531
 
527
532
  move.from.deselect();
533
+
534
+ if (!move.check()) return false;
535
+
528
536
  this.allSquares("removeHint");
529
537
 
530
538
  if (this.config.onlyLegalMoves && !move.isLegal(this.game)) return false;
@@ -579,7 +587,7 @@ class Chessboard {
579
587
  return this.game.moves({ verbose: verb });
580
588
  }
581
589
 
582
- move(move, animation) {
590
+ move(move, animation = true) {
583
591
  move = this.convertMove(move);
584
592
  move.check();
585
593
 
@@ -750,14 +758,27 @@ class Chessboard {
750
758
  }
751
759
 
752
760
  setOrientation(color, animation = true) {
753
- if (!['w', 'b'].includes(color)) {
754
- this.config.orientation = color;
755
- this.flip(animation);
761
+ if (['w', 'b'].includes(color)) {
762
+ if (color !== this.config.orientation) {
763
+ this.flip(animation);
764
+ }
756
765
  } else {
757
766
  throw new Error(this.error_messages['invalid_orientation'] + color);
758
767
  }
759
768
  }
760
769
 
770
+ highlight(squareId) {
771
+ let square = this.convertSquare(squareId);
772
+ square.check();
773
+ square.highlight();
774
+ }
775
+
776
+ dehighlight(squareId) {
777
+ let square = this.convertSquare(squareId);
778
+ square.check();
779
+ square.dehighlight();
780
+ }
781
+
761
782
  lastMove() {
762
783
  const moves = this.history({ verbose: true });
763
784
  return moves[moves.length - 1];
@@ -771,7 +792,7 @@ class Chessboard {
771
792
  }
772
793
 
773
794
  build() {
774
- if (this.board) this.destroy();
795
+ if (this.element) this.destroy();
775
796
  this.init();
776
797
  }
777
798
 
@@ -785,7 +806,12 @@ class Chessboard {
785
806
  }
786
807
 
787
808
  board() {
788
- return this.game.board();
809
+ let dict = {};
810
+ for (let squareId in this.squares) {
811
+ let piece = this.getGamePieceId(squareId);
812
+ if (piece) dict[squareId] = piece;
813
+ }
814
+ return dict;
789
815
  }
790
816
 
791
817
  clear(options = {}, animation = true) {
@@ -800,7 +826,7 @@ class Chessboard {
800
826
  get(squareId) {
801
827
  const square = this.convertSquare(squareId);
802
828
  square.check();
803
- return square.piece;
829
+ return square.piece;
804
830
  }
805
831
 
806
832
  getCastlingRights(color) {
@@ -847,9 +873,9 @@ class Chessboard {
847
873
  return this.game.isThreefoldRepetition();
848
874
  }
849
875
 
850
- load(fen, options = {}, animation = true) {
876
+ load(position, options = {}, animation = true) {
851
877
  this.clearSquares();
852
- this.game.load(fen, options);
878
+ this.setGame(position, options);
853
879
  this.updateBoardPieces(animation);
854
880
  }
855
881
 
@@ -912,7 +938,7 @@ class Chessboard {
912
938
  setHeader(key, value) {
913
939
  return this.game.setHeader(key, value);
914
940
  }
915
-
941
+
916
942
  squareColor(squareId) {
917
943
  return this.game.squareColor(squareId);
918
944
  }
@@ -21,27 +21,15 @@ class Move {
21
21
  }
22
22
 
23
23
  check() {
24
- if (this.piece === null) {
25
- throw new Error("Invalid move: piece is null");
26
- }
27
- if (!(this.piece instanceof Piece)) {
28
- throw new Error("Invalid move: piece is not an instance of Piece");
29
- }
30
- if (['q', 'r', 'b', 'n', null].indexOf(this.promotion) === -1) {
31
- throw new Error("Invalid move: promotion is not valid");
32
- }
33
- if (!(this.from instanceof Square)) {
34
- throw new Error("Invalid move: from is not an instance of Square");
35
- }
36
- if (!(this.to instanceof Square)) {
37
- throw new Error("Invalid move: to is not an instance of Square");
38
- }
39
- if (!this.to) {
40
- throw new Error("Invalid move: to is null or undefined");
41
- }
42
- if (!this.from) {
43
- throw new Error("Invalid move: from is null or undefined");
44
- }
24
+ if (this.piece === null) return false;
25
+ if (!(this.piece instanceof Piece)) return false;
26
+ if (['q', 'r', 'b', 'n', null].indexOf(this.promotion) === -1) return false;
27
+ if (!(this.from instanceof Square)) return false;
28
+ if (!(this.to instanceof Square)) return false;
29
+ if (!this.to) return false;
30
+ if (!this.from) return false;
31
+ if (this.from === this.to) return false;
32
+ return true;
45
33
  }
46
34
 
47
35
  isLegal(game) {
@@ -58,7 +58,7 @@ class Piece {
58
58
  }
59
59
 
60
60
  setDrag(f) {
61
- this.element.ondragstart = () => false;
61
+ this.element.ondragstart = (e) => { e.preventDefault() };
62
62
  this.element.onmousedown = f;
63
63
  }
64
64
 
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "chess.js": "^1.0.0"
4
4
  },
5
5
  "name": "@alepot55/chessboardjs",
6
- "version": "2.1.7",
6
+ "version": "2.2.1",
7
7
  "main": "chessboard.js",
8
8
  "type": "module",
9
9
  "scripts": {