@alepot55/chessboardjs 2.3.3 → 2.3.5
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/config/rollup.config.js +2 -1
- package/dist/chessboard.cjs.js +340 -246
- package/dist/chessboard.css +28 -6
- package/dist/chessboard.esm.js +340 -246
- package/dist/chessboard.iife.js +341 -246
- package/dist/chessboard.umd.js +340 -246
- package/package.json +6 -8
- package/src/components/Piece.js +11 -11
- package/src/components/Square.js +1 -1
- package/src/core/Chessboard.js +87 -86
- package/src/services/BoardService.js +20 -1
- package/src/services/EventService.js +131 -45
- package/src/services/MoveService.js +81 -94
- package/src/services/PieceService.js +9 -8
- package/src/styles/index.css +8 -0
- package/tests/unit/chessboard-robust.test.js +0 -44
- package/tools/build-html-examples.cjs +80 -0
- package/tools/build-html-examples.js +78 -0
- package/chessboard.bundle.js +0 -4072
package/package.json
CHANGED
|
@@ -3,17 +3,14 @@
|
|
|
3
3
|
"chess.js": "^1.0.0"
|
|
4
4
|
},
|
|
5
5
|
"name": "@alepot55/chessboardjs",
|
|
6
|
-
"version": "2.3.
|
|
6
|
+
"version": "2.3.5",
|
|
7
7
|
"main": "src/index.js",
|
|
8
8
|
"type": "module",
|
|
9
9
|
"scripts": {
|
|
10
10
|
"dev": "rollup -c config/rollup.config.js --watch",
|
|
11
|
-
"build": "
|
|
12
|
-
"build:
|
|
13
|
-
"build
|
|
14
|
-
"build:cjs": "rollup -c config/rollup.config.js --format cjs",
|
|
15
|
-
"build:umd": "rollup -c config/rollup.config.js --format umd",
|
|
16
|
-
"build:iife": "rollup -c config/rollup.config.js --format iife",
|
|
11
|
+
"build:css": "cat src/styles/board.css src/styles/pieces.css src/styles/animations.css > dist/chessboard.css",
|
|
12
|
+
"build:rollup": "rollup -c config/rollup.config.js",
|
|
13
|
+
"build": "npm run build:css && npm run build:rollup",
|
|
17
14
|
"test": "jest --config config/jest.config.js",
|
|
18
15
|
"test:watch": "jest --config config/jest.config.js --watch",
|
|
19
16
|
"test:coverage": "jest --config config/jest.config.js --coverage",
|
|
@@ -46,6 +43,7 @@
|
|
|
46
43
|
"babel-jest": "^29.7.0",
|
|
47
44
|
"jest": "^29.7.0",
|
|
48
45
|
"jest-environment-jsdom": "^29.7.0",
|
|
49
|
-
"rollup": "^4.34.7"
|
|
46
|
+
"rollup": "^4.34.7",
|
|
47
|
+
"terser": "^5.43.1"
|
|
50
48
|
}
|
|
51
49
|
}
|
package/src/components/Piece.js
CHANGED
|
@@ -194,6 +194,8 @@ class Piece {
|
|
|
194
194
|
if (callback) callback();
|
|
195
195
|
}
|
|
196
196
|
}
|
|
197
|
+
// Se l'elemento è già stato rimosso, esci subito
|
|
198
|
+
if (!this.element) { console.debug(`[Piece] fadeOut: ${this.id} - element is null (init)`); if (callback) callback(); return; }
|
|
197
199
|
fade();
|
|
198
200
|
}
|
|
199
201
|
|
|
@@ -201,24 +203,22 @@ class Piece {
|
|
|
201
203
|
if (!this.element) { console.debug(`[Piece] setDrag: ${this.id} - element is null`); return; }
|
|
202
204
|
this.element.ondragstart = (e) => { e.preventDefault() };
|
|
203
205
|
this.element.onmousedown = f;
|
|
206
|
+
this.element.ontouchstart = f; // Drag touch
|
|
204
207
|
console.debug(`[Piece] setDrag: ${this.id}`);
|
|
205
208
|
}
|
|
206
209
|
|
|
207
210
|
destroy() {
|
|
211
|
+
if (!this.element) return; // Idempotente: già rimosso
|
|
208
212
|
console.debug(`[Piece] Destroy: ${this.id}`);
|
|
209
213
|
// Remove all event listeners
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
if (this.element.parentNode) {
|
|
216
|
-
this.element.parentNode.removeChild(this.element);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// Clear references
|
|
220
|
-
this.element = null;
|
|
214
|
+
this.element.onmousedown = null;
|
|
215
|
+
this.element.ondragstart = null;
|
|
216
|
+
// Remove from DOM
|
|
217
|
+
if (this.element.parentNode) {
|
|
218
|
+
this.element.parentNode.removeChild(this.element);
|
|
221
219
|
}
|
|
220
|
+
// Clear references
|
|
221
|
+
this.element = null;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
224
|
translate(to, duration, transition_f, speed, callback = null) {
|
package/src/components/Square.js
CHANGED
|
@@ -73,8 +73,8 @@ class Square {
|
|
|
73
73
|
// Best practice: destroy the piece object if present
|
|
74
74
|
if (this.piece && typeof this.piece.destroy === 'function') {
|
|
75
75
|
this.piece.destroy();
|
|
76
|
-
this.piece = null;
|
|
77
76
|
}
|
|
77
|
+
this.piece = null;
|
|
78
78
|
// Remove any orphaned img.piece elements from the DOM
|
|
79
79
|
const pieceElements = this.element.querySelectorAll('img.piece');
|
|
80
80
|
pieceElements.forEach(element => {
|
package/src/core/Chessboard.js
CHANGED
|
@@ -656,68 +656,48 @@ class Chessboard {
|
|
|
656
656
|
* @param {boolean} [isPositionLoad=false] - Whether this is a position load (affects delay)
|
|
657
657
|
*/
|
|
658
658
|
_doUpdateBoardPieces(animation = false, isPositionLoad = false) {
|
|
659
|
+
// Blocca update se un drag è in corso
|
|
660
|
+
if (this._isDragging) return;
|
|
659
661
|
// Skip update if we're in the middle of a promotion
|
|
660
662
|
if (this._isPromoting) {
|
|
661
|
-
console.log('Skipping board update during promotion');
|
|
662
663
|
return;
|
|
663
664
|
}
|
|
664
|
-
|
|
665
|
-
// Check if services are available
|
|
666
665
|
if (!this.positionService || !this.positionService.getGame()) {
|
|
667
|
-
console.log('Cannot update board pieces - position service not available');
|
|
668
666
|
return;
|
|
669
667
|
}
|
|
670
|
-
|
|
671
668
|
const squares = this.boardService.getAllSquares();
|
|
672
669
|
const gameStateBefore = this.positionService.getGame().fen();
|
|
673
|
-
|
|
674
|
-
// PATCH ROBUSTA: se la board è completamente vuota, forza la rimozione di TUTTI i pezzi
|
|
675
670
|
if (/^8\/8\/8\/8\/8\/8\/8\/8/.test(gameStateBefore)) {
|
|
676
|
-
console.log('Board vuota rilevata - rimozione forzata di tutti i pezzi dal DOM');
|
|
677
|
-
|
|
678
|
-
// 1. Rimuovi tutti gli elementi DOM dei pezzi dal contenitore della board
|
|
679
671
|
const boardContainer = document.getElementById(this.config.id_div);
|
|
680
672
|
if (boardContainer) {
|
|
681
673
|
const pieceElements = boardContainer.querySelectorAll('.piece');
|
|
682
674
|
pieceElements.forEach(element => {
|
|
683
|
-
console.log('Rimozione forzata elemento DOM pezzo:', element);
|
|
684
675
|
element.remove();
|
|
685
676
|
});
|
|
686
677
|
}
|
|
687
|
-
|
|
688
|
-
// 2. Azzera tutti i riferimenti JS ai pezzi
|
|
689
678
|
Object.values(squares).forEach(sq => {
|
|
690
679
|
if (sq && sq.piece) {
|
|
691
|
-
console.log('Azzero riferimento pezzo su casella:', sq.id);
|
|
692
680
|
sq.piece = null;
|
|
693
681
|
}
|
|
694
682
|
});
|
|
695
|
-
|
|
696
|
-
// 3. Forza la pulizia di eventuali selezioni/hint
|
|
697
683
|
this._clearVisualState();
|
|
698
|
-
|
|
699
|
-
// 4. Aggiungi i listener e notifica il cambio
|
|
700
684
|
this._addListeners();
|
|
701
685
|
if (this.config.onChange) this.config.onChange(gameStateBefore);
|
|
702
|
-
|
|
703
|
-
console.log('Rimozione forzata completata');
|
|
704
686
|
return;
|
|
705
687
|
}
|
|
706
|
-
|
|
707
|
-
console.log('_doUpdateBoardPieces - current FEN:', gameStateBefore);
|
|
708
|
-
console.log('_doUpdateBoardPieces - animation:', animation, 'style:', this.config.animationStyle, 'isPositionLoad:', isPositionLoad);
|
|
709
|
-
|
|
710
|
-
// Determine which animation style to use
|
|
711
688
|
const useSimultaneous = this.config.animationStyle === 'simultaneous';
|
|
712
|
-
console.log('_doUpdateBoardPieces - useSimultaneous:', useSimultaneous);
|
|
713
|
-
|
|
714
689
|
if (useSimultaneous) {
|
|
715
|
-
console.log('Using simultaneous animation');
|
|
716
690
|
this._doSimultaneousUpdate(squares, gameStateBefore, isPositionLoad);
|
|
717
691
|
} else {
|
|
718
|
-
console.log('Using sequential animation');
|
|
719
692
|
this._doSequentialUpdate(squares, gameStateBefore, animation);
|
|
720
693
|
}
|
|
694
|
+
// Pulizia finale robusta: rimuovi tutti i pezzi orfani dal DOM e dal riferimento JS
|
|
695
|
+
Object.values(this.boardService.getAllSquares()).forEach(square => {
|
|
696
|
+
const expectedPieceId = this.positionService.getGamePieceId(square.id);
|
|
697
|
+
if (!expectedPieceId && typeof square.forceRemoveAllPieces === 'function') {
|
|
698
|
+
square.forceRemoveAllPieces();
|
|
699
|
+
}
|
|
700
|
+
});
|
|
721
701
|
}
|
|
722
702
|
|
|
723
703
|
/**
|
|
@@ -746,7 +726,12 @@ class Chessboard {
|
|
|
746
726
|
|
|
747
727
|
// Se c'è un pezzo attuale ma non è quello atteso, rimuovilo
|
|
748
728
|
if (currentPiece && currentPieceId !== expectedPieceId) {
|
|
749
|
-
|
|
729
|
+
// Rimozione robusta: elimina tutti i pezzi orfani dal DOM e dal riferimento JS
|
|
730
|
+
if (typeof square.forceRemoveAllPieces === 'function') {
|
|
731
|
+
square.forceRemoveAllPieces();
|
|
732
|
+
} else {
|
|
733
|
+
this.pieceService.removePieceFromSquare(square, animation);
|
|
734
|
+
}
|
|
750
735
|
}
|
|
751
736
|
|
|
752
737
|
// Se c'è un pezzo atteso ma non è quello attuale, aggiungilo
|
|
@@ -875,7 +860,13 @@ class Chessboard {
|
|
|
875
860
|
for (let i = 0; i < fromList.length; i++) {
|
|
876
861
|
if (!fromMatched[i]) {
|
|
877
862
|
setTimeout(() => {
|
|
878
|
-
|
|
863
|
+
// Rimozione robusta: elimina tutti i pezzi orfani dal DOM e dal riferimento JS
|
|
864
|
+
if (typeof fromList[i].square.forceRemoveAllPieces === 'function') {
|
|
865
|
+
fromList[i].square.forceRemoveAllPieces();
|
|
866
|
+
} else {
|
|
867
|
+
this.pieceService.removePieceFromSquare(fromList[i].square, true, onAnimationComplete);
|
|
868
|
+
}
|
|
869
|
+
onAnimationComplete();
|
|
879
870
|
}, animationIndex * animationDelay);
|
|
880
871
|
animationIndex++;
|
|
881
872
|
}
|
|
@@ -1267,6 +1258,8 @@ class Chessboard {
|
|
|
1267
1258
|
if (this._updateBoardPieces) {
|
|
1268
1259
|
this._updateBoardPieces(animate, true);
|
|
1269
1260
|
}
|
|
1261
|
+
// Forza la sincronizzazione dopo setPosition
|
|
1262
|
+
this._updateBoardPieces(true, false);
|
|
1270
1263
|
return true;
|
|
1271
1264
|
}
|
|
1272
1265
|
/**
|
|
@@ -1280,7 +1273,10 @@ class Chessboard {
|
|
|
1280
1273
|
// Use the default starting position from config or fallback
|
|
1281
1274
|
const startPosition = this.config && this.config.position ? this.config.position : 'start';
|
|
1282
1275
|
this._updateBoardPieces(animate);
|
|
1283
|
-
|
|
1276
|
+
const result = this.setPosition(startPosition, { animate });
|
|
1277
|
+
// Forza la sincronizzazione dopo reset
|
|
1278
|
+
this._updateBoardPieces(true, false);
|
|
1279
|
+
return result;
|
|
1284
1280
|
}
|
|
1285
1281
|
/**
|
|
1286
1282
|
* Clear the board
|
|
@@ -1304,6 +1300,8 @@ class Chessboard {
|
|
|
1304
1300
|
if (this._updateBoardPieces) {
|
|
1305
1301
|
this._updateBoardPieces(animate, true);
|
|
1306
1302
|
}
|
|
1303
|
+
// Forza la sincronizzazione dopo clear
|
|
1304
|
+
this._updateBoardPieces(true, false);
|
|
1307
1305
|
return true;
|
|
1308
1306
|
}
|
|
1309
1307
|
|
|
@@ -1318,7 +1316,8 @@ class Chessboard {
|
|
|
1318
1316
|
const undone = this.positionService.getGame().undo();
|
|
1319
1317
|
if (undone) {
|
|
1320
1318
|
this._undoneMoves.push(undone);
|
|
1321
|
-
|
|
1319
|
+
// Forza refresh completo di tutti i pezzi dopo undo
|
|
1320
|
+
this._updateBoardPieces(true, true);
|
|
1322
1321
|
return undone;
|
|
1323
1322
|
}
|
|
1324
1323
|
return null;
|
|
@@ -1335,7 +1334,8 @@ class Chessboard {
|
|
|
1335
1334
|
const moveObj = { from: move.from, to: move.to };
|
|
1336
1335
|
if (move.promotion) moveObj.promotion = move.promotion;
|
|
1337
1336
|
const result = this.positionService.getGame().move(moveObj);
|
|
1338
|
-
|
|
1337
|
+
// Forza refresh completo di tutti i pezzi dopo redo
|
|
1338
|
+
this._updateBoardPieces(true, true);
|
|
1339
1339
|
return result;
|
|
1340
1340
|
}
|
|
1341
1341
|
return false;
|
|
@@ -1354,17 +1354,19 @@ class Chessboard {
|
|
|
1354
1354
|
* @returns {string|null}
|
|
1355
1355
|
*/
|
|
1356
1356
|
getPiece(square) {
|
|
1357
|
-
//
|
|
1358
|
-
const
|
|
1359
|
-
if (!
|
|
1360
|
-
|
|
1357
|
+
// Sempre leggi lo stato aggiornato dal boardService
|
|
1358
|
+
const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
|
|
1359
|
+
if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[getPiece] Parametro square non valido');
|
|
1360
|
+
// Forza sync prima di leggere
|
|
1361
|
+
this._updateBoardPieces(false, false);
|
|
1362
|
+
const piece = squareObj.piece;
|
|
1361
1363
|
if (!piece) return null;
|
|
1362
1364
|
return (piece.color + piece.type).toLowerCase();
|
|
1363
1365
|
}
|
|
1364
1366
|
/**
|
|
1365
1367
|
* Put a piece on a square
|
|
1366
|
-
* @param {string} piece
|
|
1367
|
-
* @param {string} square
|
|
1368
|
+
* @param {string|Piece} piece
|
|
1369
|
+
* @param {string|Square} square
|
|
1368
1370
|
* @param {Object} [opts]
|
|
1369
1371
|
* @param {boolean} [opts.animate=true]
|
|
1370
1372
|
* @returns {boolean}
|
|
@@ -1375,7 +1377,6 @@ class Chessboard {
|
|
|
1375
1377
|
if (typeof piece === 'object' && piece.type && piece.color) {
|
|
1376
1378
|
pieceStr = (piece.color + piece.type).toLowerCase();
|
|
1377
1379
|
} else if (typeof piece === 'string' && piece.length === 2) {
|
|
1378
|
-
// Accetta sia 'wq' che 'qw', normalizza a 'wq'
|
|
1379
1380
|
const a = piece[0].toLowerCase();
|
|
1380
1381
|
const b = piece[1].toLowerCase();
|
|
1381
1382
|
const types = 'kqrbnp';
|
|
@@ -1388,42 +1389,36 @@ class Chessboard {
|
|
|
1388
1389
|
throw new Error(`[putPiece] Invalid piece: ${piece}`);
|
|
1389
1390
|
}
|
|
1390
1391
|
}
|
|
1391
|
-
const
|
|
1392
|
-
|
|
1393
|
-
if (!validSquare) throw new Error(`[putPiece] Invalid square: ${square}`);
|
|
1394
|
-
if (!validPiece) throw new Error(`[putPiece] Invalid piece: ${pieceStr}`);
|
|
1395
|
-
if (!this.positionService || !this.positionService.getGame()) {
|
|
1396
|
-
throw new Error('[putPiece] No positionService or game');
|
|
1397
|
-
}
|
|
1392
|
+
const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
|
|
1393
|
+
if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[putPiece] Parametro square non valido');
|
|
1398
1394
|
const pieceObj = this.pieceService.convertPiece(pieceStr);
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
squareObj.piece = pieceObj;
|
|
1395
|
+
if (!pieceObj || typeof pieceObj !== 'object' || !('type' in pieceObj)) throw new Error('[putPiece] Parametro piece non valido');
|
|
1396
|
+
// Aggiorna solo il motore chess.js
|
|
1402
1397
|
const chessJsPiece = { type: pieceObj.type, color: pieceObj.color };
|
|
1403
1398
|
const game = this.positionService.getGame();
|
|
1404
|
-
const result = game.put(chessJsPiece,
|
|
1405
|
-
if (!result) throw new Error(`[putPiece] Game.put failed for ${pieceStr} on ${
|
|
1399
|
+
const result = game.put(chessJsPiece, squareObj.id);
|
|
1400
|
+
if (!result) throw new Error(`[putPiece] Game.put failed for ${pieceStr} on ${squareObj.id}`);
|
|
1401
|
+
// Non aggiornare direttamente square.piece!
|
|
1402
|
+
// Riallinea la board JS allo stato del motore
|
|
1406
1403
|
this._updateBoardPieces(animate);
|
|
1407
1404
|
return true;
|
|
1408
1405
|
}
|
|
1409
1406
|
/**
|
|
1410
1407
|
* Remove a piece from a square
|
|
1411
|
-
* @param {string} square
|
|
1408
|
+
* @param {string|Square} square
|
|
1412
1409
|
* @param {Object} [opts]
|
|
1413
1410
|
* @param {boolean} [opts.animate=true]
|
|
1414
1411
|
* @returns {string|null}
|
|
1415
1412
|
*/
|
|
1416
1413
|
removePiece(square, opts = {}) {
|
|
1417
1414
|
const animate = opts.animate !== undefined ? opts.animate : true;
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
const squareObj = this.boardService.getSquare(square);
|
|
1422
|
-
if (!squareObj) return true;
|
|
1423
|
-
if (!squareObj.piece) return true;
|
|
1424
|
-
squareObj.piece = null;
|
|
1415
|
+
const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
|
|
1416
|
+
if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[removePiece] Parametro square non valido');
|
|
1417
|
+
// Aggiorna solo il motore chess.js
|
|
1425
1418
|
const game = this.positionService.getGame();
|
|
1426
|
-
game.remove(
|
|
1419
|
+
game.remove(squareObj.id);
|
|
1420
|
+
// Non aggiornare direttamente square.piece!
|
|
1421
|
+
// Riallinea la board JS allo stato del motore
|
|
1427
1422
|
this._updateBoardPieces(animate);
|
|
1428
1423
|
return true;
|
|
1429
1424
|
}
|
|
@@ -1488,28 +1483,32 @@ class Chessboard {
|
|
|
1488
1483
|
// --- HIGHLIGHTING & UI ---
|
|
1489
1484
|
/**
|
|
1490
1485
|
* Highlight a square
|
|
1491
|
-
* @param {string} square
|
|
1486
|
+
* @param {string|Square} square
|
|
1492
1487
|
* @param {Object} [opts]
|
|
1493
1488
|
*/
|
|
1494
1489
|
highlight(square, opts = {}) {
|
|
1495
|
-
|
|
1490
|
+
// API: accetta id, converte subito in oggetto
|
|
1491
|
+
const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
|
|
1492
|
+
if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[highlight] Parametro square non valido');
|
|
1496
1493
|
if (this.boardService && this.boardService.highlightSquare) {
|
|
1497
|
-
this.boardService.highlightSquare(
|
|
1494
|
+
this.boardService.highlightSquare(squareObj, opts);
|
|
1498
1495
|
} else if (this.eventService && this.eventService.highlightSquare) {
|
|
1499
|
-
this.eventService.highlightSquare(
|
|
1496
|
+
this.eventService.highlightSquare(squareObj, opts);
|
|
1500
1497
|
}
|
|
1501
1498
|
}
|
|
1502
1499
|
/**
|
|
1503
1500
|
* Remove highlight from a square
|
|
1504
|
-
* @param {string} square
|
|
1501
|
+
* @param {string|Square} square
|
|
1505
1502
|
* @param {Object} [opts]
|
|
1506
1503
|
*/
|
|
1507
1504
|
dehighlight(square, opts = {}) {
|
|
1508
|
-
|
|
1505
|
+
// API: accetta id, converte subito in oggetto
|
|
1506
|
+
const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
|
|
1507
|
+
if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[dehighlight] Parametro square non valido');
|
|
1509
1508
|
if (this.boardService && this.boardService.dehighlightSquare) {
|
|
1510
|
-
this.boardService.dehighlightSquare(
|
|
1509
|
+
this.boardService.dehighlightSquare(squareObj, opts);
|
|
1511
1510
|
} else if (this.eventService && this.eventService.dehighlightSquare) {
|
|
1512
|
-
this.eventService.dehighlightSquare(
|
|
1511
|
+
this.eventService.dehighlightSquare(squareObj, opts);
|
|
1513
1512
|
}
|
|
1514
1513
|
}
|
|
1515
1514
|
|
|
@@ -1534,6 +1533,8 @@ class Chessboard {
|
|
|
1534
1533
|
* @returns {boolean}
|
|
1535
1534
|
*/
|
|
1536
1535
|
isGameOver() {
|
|
1536
|
+
// Forza sync prima di interrogare il motore
|
|
1537
|
+
this._updateBoardPieces(false, false);
|
|
1537
1538
|
const game = this.positionService.getGame();
|
|
1538
1539
|
if (!game) return false;
|
|
1539
1540
|
if (game.isGameOver) return game.isGameOver();
|
|
@@ -1903,7 +1904,7 @@ class Chessboard {
|
|
|
1903
1904
|
dehighlightSquare(square) {
|
|
1904
1905
|
return this.boardService.dehighlight(square);
|
|
1905
1906
|
}
|
|
1906
|
-
forceSync() { this._updateBoardPieces(true, true); }
|
|
1907
|
+
forceSync() { this._updateBoardPieces(true, true); this._updateBoardPieces(true, false); }
|
|
1907
1908
|
|
|
1908
1909
|
// Metodi mancanti che causano fallimenti nei test
|
|
1909
1910
|
/**
|
|
@@ -1916,37 +1917,37 @@ class Chessboard {
|
|
|
1916
1917
|
movePiece(move, opts = {}) {
|
|
1917
1918
|
const animate = opts.animate !== undefined ? opts.animate : true;
|
|
1918
1919
|
|
|
1919
|
-
//
|
|
1920
|
-
let
|
|
1920
|
+
// --- API: accetta id/stringhe, ma converte subito in oggetti ---
|
|
1921
|
+
let fromSquareObj, toSquareObj, promotion;
|
|
1921
1922
|
if (typeof move === 'string') {
|
|
1922
1923
|
if (move.length === 4) {
|
|
1923
|
-
|
|
1924
|
-
|
|
1924
|
+
fromSquareObj = this.boardService.getSquare(move.substring(0, 2));
|
|
1925
|
+
toSquareObj = this.boardService.getSquare(move.substring(2, 4));
|
|
1925
1926
|
} else if (move.length === 5) {
|
|
1926
|
-
|
|
1927
|
-
|
|
1927
|
+
fromSquareObj = this.boardService.getSquare(move.substring(0, 2));
|
|
1928
|
+
toSquareObj = this.boardService.getSquare(move.substring(2, 4));
|
|
1928
1929
|
promotion = move.substring(4, 5);
|
|
1929
1930
|
} else {
|
|
1930
1931
|
throw new Error(`Invalid move format: ${move}`);
|
|
1931
1932
|
}
|
|
1932
1933
|
} else if (typeof move === 'object' && move.from && move.to) {
|
|
1933
|
-
|
|
1934
|
-
|
|
1934
|
+
// Se sono id, converto in oggetti; se sono già oggetti, li uso direttamente
|
|
1935
|
+
fromSquareObj = typeof move.from === 'string' ? this.boardService.getSquare(move.from) : move.from;
|
|
1936
|
+
toSquareObj = typeof move.to === 'string' ? this.boardService.getSquare(move.to) : move.to;
|
|
1935
1937
|
promotion = move.promotion;
|
|
1936
1938
|
} else {
|
|
1937
1939
|
throw new Error(`Invalid move: ${move}`);
|
|
1938
1940
|
}
|
|
1939
1941
|
|
|
1940
|
-
// Get square objects
|
|
1941
|
-
const fromSquareObj = this.boardService.getSquare(fromSquare);
|
|
1942
|
-
const toSquareObj = this.boardService.getSquare(toSquare);
|
|
1943
|
-
|
|
1944
1942
|
if (!fromSquareObj || !toSquareObj) {
|
|
1945
|
-
throw new Error(`Invalid squares: ${
|
|
1943
|
+
throw new Error(`Invalid squares: ${move.from || move.substring(0, 2)} or ${move.to || move.substring(2, 4)}`);
|
|
1946
1944
|
}
|
|
1947
1945
|
|
|
1948
|
-
//
|
|
1949
|
-
|
|
1946
|
+
// --- Internamente: lavora solo con oggetti ---
|
|
1947
|
+
const result = this._onMove(fromSquareObj, toSquareObj, promotion, animate);
|
|
1948
|
+
// Dopo ogni mossa, forza la sincronizzazione della board
|
|
1949
|
+
this._updateBoardPieces(true, false);
|
|
1950
|
+
return result;
|
|
1950
1951
|
}
|
|
1951
1952
|
|
|
1952
1953
|
// Aliases for backward compatibility
|
|
@@ -116,13 +116,32 @@ export class BoardService {
|
|
|
116
116
|
|
|
117
117
|
/**
|
|
118
118
|
* Gets a square by its ID
|
|
119
|
-
* @param {string} squareId - Square identifier (
|
|
119
|
+
* @param {string} squareId - Square identifier (API pubblica)
|
|
120
120
|
* @returns {Square|null} The square or null if not found
|
|
121
121
|
*/
|
|
122
122
|
getSquare(squareId) {
|
|
123
123
|
return this.squares[squareId] || null;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Highlight a square (solo oggetto)
|
|
128
|
+
* @param {Square} square
|
|
129
|
+
* @param {Object} [opts]
|
|
130
|
+
*/
|
|
131
|
+
highlightSquare(square, opts = {}) {
|
|
132
|
+
if (!square) throw new Error('highlightSquare richiede oggetto Square');
|
|
133
|
+
// ... logica esistente ...
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Dehighlight a square (solo oggetto)
|
|
137
|
+
* @param {Square} square
|
|
138
|
+
* @param {Object} [opts]
|
|
139
|
+
*/
|
|
140
|
+
dehighlightSquare(square, opts = {}) {
|
|
141
|
+
if (!square) throw new Error('dehighlightSquare richiede oggetto Square');
|
|
142
|
+
// ... logica esistente ...
|
|
143
|
+
}
|
|
144
|
+
|
|
126
145
|
/**
|
|
127
146
|
* Gets all squares
|
|
128
147
|
* @returns {Object.<string, Square>} All squares indexed by ID
|