@alepot55/chessboardjs 2.3.5 → 2.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chessboard.cjs.js +127 -246
- package/dist/chessboard.esm.js +127 -246
- package/dist/chessboard.iife.js +127 -246
- package/dist/chessboard.umd.js +127 -246
- package/package.json +1 -1
- package/src/core/Chessboard.js +117 -201
- package/src/core/ChessboardConfig.js +0 -16
- package/src/core/ChessboardFactory.js +0 -5
- package/src/errors/messages.js +0 -1
- package/src/services/PieceService.js +9 -3
- package/src/services/ValidationService.js +1 -14
- package/src/utils/validation.js +1 -5
- package/tests/unit/chessboard-config-animations.test.js +0 -9
package/dist/chessboard.cjs.js
CHANGED
|
@@ -128,7 +128,6 @@ const ERROR_MESSAGES = Object.freeze({
|
|
|
128
128
|
invalid_fadeTime: 'Invalid fadeTime: ',
|
|
129
129
|
invalid_fadeAnimation: 'Invalid fadeAnimation: ',
|
|
130
130
|
invalid_ratio: 'Invalid ratio: ',
|
|
131
|
-
invalid_animationStyle: 'Invalid animationStyle: ',
|
|
132
131
|
animation_failed: 'Animation failed: ',
|
|
133
132
|
|
|
134
133
|
// Event handlers
|
|
@@ -380,7 +379,6 @@ const VALID_VALUES = Object.freeze({
|
|
|
380
379
|
movableColors: ['w', 'b', 'white', 'black', 'both', 'none'],
|
|
381
380
|
dropOffBoard: ['snapback', 'trash'],
|
|
382
381
|
easingTypes: ['linear', 'ease', 'ease-in', 'ease-out', 'ease-in-out'],
|
|
383
|
-
animationStyles: ['sequential', 'simultaneous'],
|
|
384
382
|
modes: ['normal', 'creative', 'analysis'],
|
|
385
383
|
promotionPieces: ['q', 'r', 'b', 'n', 'Q', 'R', 'B', 'N']
|
|
386
384
|
});
|
|
@@ -709,14 +707,6 @@ class ValidationService {
|
|
|
709
707
|
return this._validValues.easingTypes.includes(easing);
|
|
710
708
|
}
|
|
711
709
|
|
|
712
|
-
/**
|
|
713
|
-
* Validates animation style
|
|
714
|
-
* @param {string} style - Animation style to validate
|
|
715
|
-
* @returns {boolean} True if valid
|
|
716
|
-
*/
|
|
717
|
-
isValidAnimationStyle(style) {
|
|
718
|
-
return this._validValues.animationStyles.includes(style);
|
|
719
|
-
}
|
|
720
710
|
|
|
721
711
|
/**
|
|
722
712
|
* Validates CSS color format
|
|
@@ -913,11 +903,7 @@ class ValidationService {
|
|
|
913
903
|
if (config.dropOffBoard && !this.isValidDropOffBoard(config.dropOffBoard)) {
|
|
914
904
|
errors.push(ERROR_MESSAGES.invalid_dropOffBoard + config.dropOffBoard);
|
|
915
905
|
}
|
|
916
|
-
|
|
917
|
-
if (config.animationStyle && !this.isValidAnimationStyle(config.animationStyle)) {
|
|
918
|
-
errors.push(ERROR_MESSAGES.invalid_animationStyle + config.animationStyle);
|
|
919
|
-
}
|
|
920
|
-
|
|
906
|
+
|
|
921
907
|
// Validate callbacks
|
|
922
908
|
const callbacks = ['onMove', 'onMoveEnd', 'onChange', 'onDragStart', 'onDragMove', 'onDrop', 'onSnapbackEnd'];
|
|
923
909
|
for (const callback of callbacks) {
|
|
@@ -1095,7 +1081,6 @@ const DEFAULT_CONFIG$1 = Object.freeze({
|
|
|
1095
1081
|
fadeAnimation: 'ease',
|
|
1096
1082
|
ratio: 0.9,
|
|
1097
1083
|
piecesPath: '../assets/themes/default',
|
|
1098
|
-
animationStyle: 'simultaneous',
|
|
1099
1084
|
simultaneousAnimationDelay: 100,
|
|
1100
1085
|
onMove: () => true,
|
|
1101
1086
|
onMoveEnd: () => true,
|
|
@@ -1221,7 +1206,6 @@ class ChessboardConfig {
|
|
|
1221
1206
|
this.fadeTime = this._setTime(config.fadeTime);
|
|
1222
1207
|
|
|
1223
1208
|
// Animation style properties
|
|
1224
|
-
this.animationStyle = this._validateAnimationStyle(config.animationStyle);
|
|
1225
1209
|
this.simultaneousAnimationDelay = this._validateDelay(config.simultaneousAnimationDelay);
|
|
1226
1210
|
}
|
|
1227
1211
|
|
|
@@ -1282,19 +1266,6 @@ class ChessboardConfig {
|
|
|
1282
1266
|
return callback;
|
|
1283
1267
|
}
|
|
1284
1268
|
|
|
1285
|
-
/**
|
|
1286
|
-
* Validates animation style
|
|
1287
|
-
* @private
|
|
1288
|
-
* @param {string} style - Animation style
|
|
1289
|
-
* @returns {string} Validated style
|
|
1290
|
-
* @throws {ConfigurationError} If style is invalid
|
|
1291
|
-
*/
|
|
1292
|
-
_validateAnimationStyle(style) {
|
|
1293
|
-
if (!this._validationService.isValidAnimationStyle(style)) {
|
|
1294
|
-
throw new ConfigurationError('Invalid animation style', 'animationStyle', style);
|
|
1295
|
-
}
|
|
1296
|
-
return style;
|
|
1297
|
-
}
|
|
1298
1269
|
|
|
1299
1270
|
/**
|
|
1300
1271
|
* Validates animation delay
|
|
@@ -1432,7 +1403,6 @@ class ChessboardConfig {
|
|
|
1432
1403
|
fadeTime: this.fadeTime,
|
|
1433
1404
|
fadeAnimation: this.fadeAnimation,
|
|
1434
1405
|
piecesPath: this.piecesPath,
|
|
1435
|
-
animationStyle: this.animationStyle,
|
|
1436
1406
|
simultaneousAnimationDelay: this.simultaneousAnimationDelay,
|
|
1437
1407
|
onlyLegalMoves: this.onlyLegalMoves
|
|
1438
1408
|
};
|
|
@@ -4655,9 +4625,15 @@ class PieceService {
|
|
|
4655
4625
|
console.debug(`[PieceService] addPieceOnSquare: ${piece.id} to ${square.id}`);
|
|
4656
4626
|
square.putPiece(piece);
|
|
4657
4627
|
|
|
4628
|
+
// Imposta sempre il drag (touch e mouse)
|
|
4658
4629
|
if (dragFunction) {
|
|
4659
4630
|
piece.setDrag(dragFunction(square, piece));
|
|
4660
4631
|
}
|
|
4632
|
+
// Forza il drag touch se manca (debug/robustezza)
|
|
4633
|
+
if (!piece.element.ontouchstart) {
|
|
4634
|
+
piece.element.ontouchstart = dragFunction ? dragFunction(square, piece) : () => { };
|
|
4635
|
+
console.debug(`[PieceService] Forzato ontouchstart su ${piece.id}`);
|
|
4636
|
+
}
|
|
4661
4637
|
|
|
4662
4638
|
if (fade && this.config.fadeTime > 0) {
|
|
4663
4639
|
piece.fadeIn(
|
|
@@ -4715,8 +4691,8 @@ class PieceService {
|
|
|
4715
4691
|
*/
|
|
4716
4692
|
movePiece(piece, targetSquare, duration, callback) {
|
|
4717
4693
|
console.debug(`[PieceService] movePiece: ${piece.id} to ${targetSquare.id}`);
|
|
4718
|
-
if (!piece) {
|
|
4719
|
-
console.warn(
|
|
4694
|
+
if (!piece || !piece.element) {
|
|
4695
|
+
console.warn(`[PieceService] movePiece: piece or element is null, skipping animation`);
|
|
4720
4696
|
if (callback) callback();
|
|
4721
4697
|
return;
|
|
4722
4698
|
}
|
|
@@ -4772,7 +4748,7 @@ class PieceService {
|
|
|
4772
4748
|
};
|
|
4773
4749
|
|
|
4774
4750
|
// Check if piece is currently being dragged
|
|
4775
|
-
const isDragging = move.piece.element.classList.contains('dragging');
|
|
4751
|
+
const isDragging = move.piece.element && move.piece.element.classList.contains('dragging');
|
|
4776
4752
|
|
|
4777
4753
|
if (isDragging) {
|
|
4778
4754
|
// If piece is being dragged, don't animate - just move it immediately
|
|
@@ -7497,7 +7473,7 @@ let Chessboard$1 = class Chessboard {
|
|
|
7497
7473
|
const capturedPiece = move.to.piece;
|
|
7498
7474
|
|
|
7499
7475
|
// For castle moves in simultaneous mode, we need to coordinate both animations
|
|
7500
|
-
if (isCastleMove
|
|
7476
|
+
if (isCastleMove) {
|
|
7501
7477
|
// Start king animation
|
|
7502
7478
|
this.pieceService.translatePiece(
|
|
7503
7479
|
move,
|
|
@@ -7722,172 +7698,62 @@ let Chessboard$1 = class Chessboard {
|
|
|
7722
7698
|
}
|
|
7723
7699
|
|
|
7724
7700
|
/**
|
|
7725
|
-
*
|
|
7701
|
+
* Aggiorna i pezzi sulla scacchiera con animazione e delay configurabile (greedy matching)
|
|
7726
7702
|
* @private
|
|
7727
|
-
* @param {boolean} [animation=false] -
|
|
7728
|
-
* @param {boolean} [isPositionLoad=false] -
|
|
7703
|
+
* @param {boolean} [animation=false] - Se animare
|
|
7704
|
+
* @param {boolean} [isPositionLoad=false] - Se è un caricamento posizione (delay 0)
|
|
7729
7705
|
*/
|
|
7730
7706
|
_doUpdateBoardPieces(animation = false, isPositionLoad = false) {
|
|
7731
|
-
// Blocca update se un drag è in corso
|
|
7732
7707
|
if (this._isDragging) return;
|
|
7733
|
-
|
|
7734
|
-
if (this.
|
|
7735
|
-
return;
|
|
7736
|
-
}
|
|
7737
|
-
if (!this.positionService || !this.positionService.getGame()) {
|
|
7738
|
-
return;
|
|
7739
|
-
}
|
|
7708
|
+
if (this._isPromoting) return;
|
|
7709
|
+
if (!this.positionService || !this.positionService.getGame()) return;
|
|
7740
7710
|
const squares = this.boardService.getAllSquares();
|
|
7741
7711
|
const gameStateBefore = this.positionService.getGame().fen();
|
|
7742
7712
|
if (/^8\/8\/8\/8\/8\/8\/8\/8/.test(gameStateBefore)) {
|
|
7743
7713
|
const boardContainer = document.getElementById(this.config.id_div);
|
|
7744
7714
|
if (boardContainer) {
|
|
7745
7715
|
const pieceElements = boardContainer.querySelectorAll('.piece');
|
|
7746
|
-
pieceElements.forEach(element =>
|
|
7747
|
-
element.remove();
|
|
7748
|
-
});
|
|
7716
|
+
pieceElements.forEach(element => element.remove());
|
|
7749
7717
|
}
|
|
7750
|
-
Object.values(squares).forEach(sq => {
|
|
7751
|
-
if (sq && sq.piece) {
|
|
7752
|
-
sq.piece = null;
|
|
7753
|
-
}
|
|
7754
|
-
});
|
|
7718
|
+
Object.values(squares).forEach(sq => { if (sq && sq.piece) sq.piece = null; });
|
|
7755
7719
|
this._clearVisualState();
|
|
7756
7720
|
this._addListeners();
|
|
7757
7721
|
if (this.config.onChange) this.config.onChange(gameStateBefore);
|
|
7758
7722
|
return;
|
|
7759
7723
|
}
|
|
7760
|
-
const useSimultaneous = this.config.animationStyle === 'simultaneous';
|
|
7761
|
-
if (useSimultaneous) {
|
|
7762
|
-
this._doSimultaneousUpdate(squares, gameStateBefore, isPositionLoad);
|
|
7763
|
-
} else {
|
|
7764
|
-
this._doSequentialUpdate(squares, gameStateBefore, animation);
|
|
7765
|
-
}
|
|
7766
|
-
// Pulizia finale robusta: rimuovi tutti i pezzi orfani dal DOM e dal riferimento JS
|
|
7767
|
-
Object.values(this.boardService.getAllSquares()).forEach(square => {
|
|
7768
|
-
const expectedPieceId = this.positionService.getGamePieceId(square.id);
|
|
7769
|
-
if (!expectedPieceId && typeof square.forceRemoveAllPieces === 'function') {
|
|
7770
|
-
square.forceRemoveAllPieces();
|
|
7771
|
-
}
|
|
7772
|
-
});
|
|
7773
|
-
}
|
|
7774
7724
|
|
|
7775
|
-
|
|
7776
|
-
* Performs sequential piece updates (original behavior)
|
|
7777
|
-
* @private
|
|
7778
|
-
* @param {Object} squares - All squares
|
|
7779
|
-
* @param {string} gameStateBefore - Game state before update
|
|
7780
|
-
* @param {boolean} animation - Whether to animate
|
|
7781
|
-
*/
|
|
7782
|
-
_doSequentialUpdate(squares, gameStateBefore, animation) {
|
|
7783
|
-
// Mappa: squareId -> expectedPieceId
|
|
7784
|
-
const expectedMap = {};
|
|
7785
|
-
Object.values(squares).forEach(square => {
|
|
7786
|
-
expectedMap[square.id] = this.positionService.getGamePieceId(square.id);
|
|
7787
|
-
});
|
|
7788
|
-
|
|
7789
|
-
Object.values(squares).forEach(square => {
|
|
7790
|
-
const expectedPieceId = expectedMap[square.id];
|
|
7791
|
-
const currentPiece = square.piece;
|
|
7792
|
-
const currentPieceId = currentPiece ? currentPiece.getId() : null;
|
|
7793
|
-
|
|
7794
|
-
// Se il pezzo attuale e quello atteso sono identici, non fare nulla
|
|
7795
|
-
if (currentPieceId === expectedPieceId) {
|
|
7796
|
-
return;
|
|
7797
|
-
}
|
|
7798
|
-
|
|
7799
|
-
// Se c'è un pezzo attuale ma non è quello atteso, rimuovilo
|
|
7800
|
-
if (currentPiece && currentPieceId !== expectedPieceId) {
|
|
7801
|
-
// Rimozione robusta: elimina tutti i pezzi orfani dal DOM e dal riferimento JS
|
|
7802
|
-
if (typeof square.forceRemoveAllPieces === 'function') {
|
|
7803
|
-
square.forceRemoveAllPieces();
|
|
7804
|
-
} else {
|
|
7805
|
-
this.pieceService.removePieceFromSquare(square, animation);
|
|
7806
|
-
}
|
|
7807
|
-
}
|
|
7808
|
-
|
|
7809
|
-
// Se c'è un pezzo atteso ma non è quello attuale, aggiungilo
|
|
7810
|
-
if (expectedPieceId && currentPieceId !== expectedPieceId) {
|
|
7811
|
-
const newPiece = this.pieceService.convertPiece(expectedPieceId);
|
|
7812
|
-
this.pieceService.addPieceOnSquare(
|
|
7813
|
-
square,
|
|
7814
|
-
newPiece,
|
|
7815
|
-
animation,
|
|
7816
|
-
this._createDragFunction.bind(this)
|
|
7817
|
-
);
|
|
7818
|
-
}
|
|
7819
|
-
});
|
|
7820
|
-
|
|
7821
|
-
this._addListeners();
|
|
7822
|
-
const gameStateAfter = this.positionService.getGame().fen();
|
|
7823
|
-
if (gameStateBefore !== gameStateAfter) {
|
|
7824
|
-
this.config.onChange(gameStateAfter);
|
|
7825
|
-
}
|
|
7826
|
-
}
|
|
7827
|
-
|
|
7828
|
-
/**
|
|
7829
|
-
* Performs simultaneous piece updates
|
|
7830
|
-
* @private
|
|
7831
|
-
* @param {Object} squares - All squares
|
|
7832
|
-
* @param {string} gameStateBefore - Game state before update
|
|
7833
|
-
* @param {boolean} [isPositionLoad=false] - Whether this is a position load
|
|
7834
|
-
*/
|
|
7835
|
-
_doSimultaneousUpdate(squares, gameStateBefore, isPositionLoad = false) {
|
|
7836
|
-
// Matching greedy per distanza minima, robusto
|
|
7725
|
+
// --- Matching greedy tra attuale e atteso ---
|
|
7837
7726
|
const currentMap = {};
|
|
7838
7727
|
const expectedMap = {};
|
|
7839
|
-
|
|
7840
7728
|
Object.values(squares).forEach(square => {
|
|
7841
7729
|
const currentPiece = square.piece;
|
|
7842
7730
|
const expectedPieceId = this.positionService.getGamePieceId(square.id);
|
|
7843
7731
|
if (currentPiece) {
|
|
7844
|
-
// Normalizza la chiave come 'color+type' lowercase
|
|
7845
7732
|
const key = (currentPiece.color + currentPiece.type).toLowerCase();
|
|
7846
7733
|
if (!currentMap[key]) currentMap[key] = [];
|
|
7847
|
-
currentMap[key].push({ square, id: square.id });
|
|
7734
|
+
currentMap[key].push({ square, id: square.id, piece: currentPiece });
|
|
7848
7735
|
}
|
|
7849
7736
|
if (expectedPieceId) {
|
|
7850
|
-
// Normalizza la chiave come 'color+type' lowercase
|
|
7851
7737
|
const key = expectedPieceId.toLowerCase();
|
|
7852
7738
|
if (!expectedMap[key]) expectedMap[key] = [];
|
|
7853
7739
|
expectedMap[key].push({ square, id: square.id });
|
|
7854
7740
|
}
|
|
7855
7741
|
});
|
|
7856
|
-
|
|
7857
|
-
let animationsCompleted = 0;
|
|
7742
|
+
const animationDelay = isPositionLoad ? 0 : this.config.simultaneousAnimationDelay || 0;
|
|
7858
7743
|
let totalAnimations = 0;
|
|
7859
|
-
|
|
7860
|
-
let animationIndex = 0;
|
|
7861
|
-
|
|
7862
|
-
Object.keys(expectedMap).forEach(key => {
|
|
7863
|
-
totalAnimations += Math.max((currentMap[key] || []).length, expectedMap[key].length);
|
|
7864
|
-
});
|
|
7865
|
-
|
|
7866
|
-
if (totalAnimations === 0) {
|
|
7867
|
-
this._addListeners();
|
|
7868
|
-
const gameStateAfter = this.positionService.getGame().fen();
|
|
7869
|
-
if (gameStateBefore !== gameStateAfter) {
|
|
7870
|
-
this.config.onChange(gameStateAfter);
|
|
7871
|
-
}
|
|
7872
|
-
return;
|
|
7873
|
-
}
|
|
7874
|
-
|
|
7875
|
-
const onAnimationComplete = () => {
|
|
7876
|
-
animationsCompleted++;
|
|
7877
|
-
if (animationsCompleted === totalAnimations) {
|
|
7878
|
-
this._addListeners();
|
|
7879
|
-
const gameStateAfter = this.positionService.getGame().fen();
|
|
7880
|
-
if (gameStateBefore !== gameStateAfter) {
|
|
7881
|
-
this.config.onChange(gameStateAfter);
|
|
7882
|
-
}
|
|
7883
|
-
}
|
|
7884
|
-
};
|
|
7744
|
+
let animationsCompleted = 0;
|
|
7885
7745
|
|
|
7746
|
+
// 1. Matching greedy: trova i movimenti
|
|
7747
|
+
const moves = [];
|
|
7748
|
+
const fromMatched = {};
|
|
7749
|
+
const toMatched = {};
|
|
7750
|
+
const unchanged = [];
|
|
7886
7751
|
Object.keys(expectedMap).forEach(key => {
|
|
7887
7752
|
const fromList = (currentMap[key] || []).slice();
|
|
7888
7753
|
const toList = expectedMap[key].slice();
|
|
7889
|
-
|
|
7890
|
-
|
|
7754
|
+
const localFromMatched = new Array(fromList.length).fill(false);
|
|
7755
|
+
const localToMatched = new Array(toList.length).fill(false);
|
|
7756
|
+
// Matrice delle distanze
|
|
7891
7757
|
const distances = [];
|
|
7892
7758
|
for (let i = 0; i < fromList.length; i++) {
|
|
7893
7759
|
distances[i] = [];
|
|
@@ -7896,18 +7762,12 @@ let Chessboard$1 = class Chessboard {
|
|
|
7896
7762
|
Math.abs(fromList[i].square.col - toList[j].square.col);
|
|
7897
7763
|
}
|
|
7898
7764
|
}
|
|
7899
|
-
|
|
7900
|
-
// 2. Matching greedy: abbina i più vicini
|
|
7901
|
-
const fromMatched = new Array(fromList.length).fill(false);
|
|
7902
|
-
const toMatched = new Array(toList.length).fill(false);
|
|
7903
|
-
const moves = [];
|
|
7904
|
-
|
|
7905
7765
|
while (true) {
|
|
7906
7766
|
let minDist = Infinity, minI = -1, minJ = -1;
|
|
7907
7767
|
for (let i = 0; i < fromList.length; i++) {
|
|
7908
|
-
if (
|
|
7768
|
+
if (localFromMatched[i]) continue;
|
|
7909
7769
|
for (let j = 0; j < toList.length; j++) {
|
|
7910
|
-
if (
|
|
7770
|
+
if (localToMatched[j]) continue;
|
|
7911
7771
|
if (distances[i][j] < minDist) {
|
|
7912
7772
|
minDist = distances[i][j];
|
|
7913
7773
|
minI = i;
|
|
@@ -7916,64 +7776,111 @@ let Chessboard$1 = class Chessboard {
|
|
|
7916
7776
|
}
|
|
7917
7777
|
}
|
|
7918
7778
|
if (minI === -1 || minJ === -1) break;
|
|
7919
|
-
// Se la posizione è la stessa, non fare nulla (pezzo unchanged)
|
|
7920
|
-
if (fromList[minI].square === toList[minJ].square) {
|
|
7921
|
-
|
|
7922
|
-
|
|
7779
|
+
// Se la posizione è la stessa E il Piece è lo stesso oggetto, non fare nulla (pezzo unchanged)
|
|
7780
|
+
if (fromList[minI].square === toList[minJ].square && squares[toList[minJ].square.id].piece === fromList[minI].piece) {
|
|
7781
|
+
unchanged.push({ square: fromList[minI].square, piece: fromList[minI].piece });
|
|
7782
|
+
localFromMatched[minI] = true;
|
|
7783
|
+
localToMatched[minJ] = true;
|
|
7784
|
+
fromMatched[fromList[minI].square.id] = true;
|
|
7785
|
+
toMatched[toList[minJ].square.id] = true;
|
|
7923
7786
|
continue;
|
|
7924
7787
|
}
|
|
7925
7788
|
// Altrimenti, sposta il pezzo
|
|
7926
|
-
moves.push({ from: fromList[minI].square, to: toList[minJ].square, piece: fromList[minI].
|
|
7927
|
-
|
|
7928
|
-
|
|
7789
|
+
moves.push({ from: fromList[minI].square, to: toList[minJ].square, piece: fromList[minI].piece });
|
|
7790
|
+
localFromMatched[minI] = true;
|
|
7791
|
+
localToMatched[minJ] = true;
|
|
7792
|
+
fromMatched[fromList[minI].square.id] = true;
|
|
7793
|
+
toMatched[toList[minJ].square.id] = true;
|
|
7929
7794
|
}
|
|
7795
|
+
});
|
|
7930
7796
|
|
|
7931
|
-
|
|
7932
|
-
|
|
7933
|
-
|
|
7934
|
-
|
|
7935
|
-
|
|
7936
|
-
|
|
7937
|
-
|
|
7938
|
-
|
|
7939
|
-
|
|
7940
|
-
|
|
7941
|
-
|
|
7942
|
-
|
|
7943
|
-
|
|
7797
|
+
// 2. Rimozione: pezzi presenti solo in attuale (non matched)
|
|
7798
|
+
const removes = [];
|
|
7799
|
+
Object.keys(currentMap).forEach(key => {
|
|
7800
|
+
currentMap[key].forEach(({ square, piece }) => {
|
|
7801
|
+
if (!fromMatched[square.id]) {
|
|
7802
|
+
removes.push({ square, piece });
|
|
7803
|
+
}
|
|
7804
|
+
});
|
|
7805
|
+
});
|
|
7806
|
+
|
|
7807
|
+
// 3. Aggiunta: pezzi presenti solo in atteso (non matched)
|
|
7808
|
+
const adds = [];
|
|
7809
|
+
Object.keys(expectedMap).forEach(key => {
|
|
7810
|
+
expectedMap[key].forEach(({ square, id }) => {
|
|
7811
|
+
if (!toMatched[square.id]) {
|
|
7812
|
+
adds.push({ square, pieceId: key });
|
|
7944
7813
|
}
|
|
7814
|
+
});
|
|
7815
|
+
});
|
|
7816
|
+
|
|
7817
|
+
totalAnimations = moves.length + removes.length + adds.length;
|
|
7818
|
+
if (totalAnimations === 0) {
|
|
7819
|
+
this._addListeners();
|
|
7820
|
+
const gameStateAfter = this.positionService.getGame().fen();
|
|
7821
|
+
if (gameStateBefore !== gameStateAfter) {
|
|
7822
|
+
this.config.onChange(gameStateAfter);
|
|
7945
7823
|
}
|
|
7824
|
+
return;
|
|
7825
|
+
}
|
|
7946
7826
|
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
|
|
7950
|
-
|
|
7951
|
-
|
|
7952
|
-
|
|
7953
|
-
|
|
7954
|
-
|
|
7955
|
-
|
|
7956
|
-
|
|
7957
|
-
|
|
7958
|
-
|
|
7959
|
-
|
|
7960
|
-
|
|
7827
|
+
// Debug: logga i pezzi unchanged
|
|
7828
|
+
if (unchanged.length > 0) {
|
|
7829
|
+
console.debug('[Chessboard] Unchanged pieces:', unchanged.map(u => u.piece.id + '@' + u.square.id));
|
|
7830
|
+
}
|
|
7831
|
+
|
|
7832
|
+
const onAnimationComplete = () => {
|
|
7833
|
+
animationsCompleted++;
|
|
7834
|
+
if (animationsCompleted === totalAnimations) {
|
|
7835
|
+
// Pulizia finale robusta: rimuovi tutti i pezzi orfani dal DOM e dal riferimento JS
|
|
7836
|
+
Object.values(this.boardService.getAllSquares()).forEach(square => {
|
|
7837
|
+
const expectedPieceId = this.positionService.getGamePieceId(square.id);
|
|
7838
|
+
if (!expectedPieceId && typeof square.forceRemoveAllPieces === 'function') {
|
|
7839
|
+
square.forceRemoveAllPieces();
|
|
7840
|
+
}
|
|
7841
|
+
});
|
|
7842
|
+
this._addListeners();
|
|
7843
|
+
const gameStateAfter = this.positionService.getGame().fen();
|
|
7844
|
+
if (gameStateBefore !== gameStateAfter) {
|
|
7845
|
+
this.config.onChange(gameStateAfter);
|
|
7961
7846
|
}
|
|
7962
7847
|
}
|
|
7848
|
+
};
|
|
7963
7849
|
|
|
7964
|
-
|
|
7965
|
-
|
|
7966
|
-
|
|
7967
|
-
|
|
7968
|
-
|
|
7969
|
-
|
|
7970
|
-
|
|
7971
|
-
|
|
7972
|
-
|
|
7973
|
-
|
|
7974
|
-
|
|
7975
|
-
|
|
7976
|
-
|
|
7850
|
+
// 4. Esegui tutte le animazioni con delay
|
|
7851
|
+
let idx = 0;
|
|
7852
|
+
moves.forEach(move => {
|
|
7853
|
+
setTimeout(() => {
|
|
7854
|
+
this.pieceService.translatePiece(
|
|
7855
|
+
move,
|
|
7856
|
+
false,
|
|
7857
|
+
animation,
|
|
7858
|
+
this._createDragFunction.bind(this),
|
|
7859
|
+
onAnimationComplete
|
|
7860
|
+
);
|
|
7861
|
+
}, idx++ * animationDelay);
|
|
7862
|
+
});
|
|
7863
|
+
removes.forEach(op => {
|
|
7864
|
+
setTimeout(() => {
|
|
7865
|
+
if (typeof op.square.forceRemoveAllPieces === 'function') {
|
|
7866
|
+
op.square.forceRemoveAllPieces();
|
|
7867
|
+
onAnimationComplete();
|
|
7868
|
+
} else {
|
|
7869
|
+
this.pieceService.removePieceFromSquare(op.square, animation, onAnimationComplete);
|
|
7870
|
+
}
|
|
7871
|
+
}, idx++ * animationDelay);
|
|
7872
|
+
});
|
|
7873
|
+
adds.forEach(op => {
|
|
7874
|
+
setTimeout(() => {
|
|
7875
|
+
const newPiece = this.pieceService.convertPiece(op.pieceId);
|
|
7876
|
+
this.pieceService.addPieceOnSquare(
|
|
7877
|
+
op.square,
|
|
7878
|
+
newPiece,
|
|
7879
|
+
animation,
|
|
7880
|
+
this._createDragFunction.bind(this),
|
|
7881
|
+
onAnimationComplete
|
|
7882
|
+
);
|
|
7883
|
+
}, idx++ * animationDelay);
|
|
7977
7884
|
});
|
|
7978
7885
|
}
|
|
7979
7886
|
|
|
@@ -8910,23 +8817,6 @@ let Chessboard$1 = class Chessboard {
|
|
|
8910
8817
|
}
|
|
8911
8818
|
}
|
|
8912
8819
|
|
|
8913
|
-
/**
|
|
8914
|
-
* Gets or sets the animation style
|
|
8915
|
-
* @param {string} [style] - New animation style ('sequential' or 'simultaneous')
|
|
8916
|
-
* @returns {string} Current animation style
|
|
8917
|
-
*/
|
|
8918
|
-
animationStyle(style) {
|
|
8919
|
-
if (style === undefined) {
|
|
8920
|
-
return this.config.animationStyle;
|
|
8921
|
-
}
|
|
8922
|
-
|
|
8923
|
-
if (this.validationService.isValidAnimationStyle(style)) {
|
|
8924
|
-
this.config.animationStyle = style;
|
|
8925
|
-
}
|
|
8926
|
-
|
|
8927
|
-
return this.config.animationStyle;
|
|
8928
|
-
}
|
|
8929
|
-
|
|
8930
8820
|
/**
|
|
8931
8821
|
* Gets or sets the simultaneous animation delay
|
|
8932
8822
|
* @param {number} [delay] - New delay in milliseconds
|
|
@@ -9494,7 +9384,6 @@ class ChessboardFactory {
|
|
|
9494
9384
|
hints: true,
|
|
9495
9385
|
clickable: true,
|
|
9496
9386
|
moveHighlight: true,
|
|
9497
|
-
animationStyle: 'simultaneous'
|
|
9498
9387
|
});
|
|
9499
9388
|
|
|
9500
9389
|
// Tournament template
|
|
@@ -9505,7 +9394,6 @@ class ChessboardFactory {
|
|
|
9505
9394
|
clickable: true,
|
|
9506
9395
|
moveHighlight: true,
|
|
9507
9396
|
onlyLegalMoves: true,
|
|
9508
|
-
animationStyle: 'sequential'
|
|
9509
9397
|
});
|
|
9510
9398
|
|
|
9511
9399
|
// Analysis template
|
|
@@ -9516,7 +9404,6 @@ class ChessboardFactory {
|
|
|
9516
9404
|
clickable: true,
|
|
9517
9405
|
moveHighlight: true,
|
|
9518
9406
|
mode: 'analysis',
|
|
9519
|
-
animationStyle: 'simultaneous'
|
|
9520
9407
|
});
|
|
9521
9408
|
|
|
9522
9409
|
// Puzzle template
|
|
@@ -9527,7 +9414,6 @@ class ChessboardFactory {
|
|
|
9527
9414
|
clickable: true,
|
|
9528
9415
|
moveHighlight: true,
|
|
9529
9416
|
onlyLegalMoves: true,
|
|
9530
|
-
animationStyle: 'sequential'
|
|
9531
9417
|
});
|
|
9532
9418
|
|
|
9533
9419
|
// Demo template
|
|
@@ -9537,7 +9423,6 @@ class ChessboardFactory {
|
|
|
9537
9423
|
hints: false,
|
|
9538
9424
|
clickable: false,
|
|
9539
9425
|
moveHighlight: true,
|
|
9540
|
-
animationStyle: 'simultaneous'
|
|
9541
9426
|
});
|
|
9542
9427
|
}
|
|
9543
9428
|
|
|
@@ -10345,11 +10230,7 @@ function validateConfig(config) {
|
|
|
10345
10230
|
if (config.moveAnimation && !isValidEasing(config.moveAnimation)) {
|
|
10346
10231
|
errors.push('Invalid moveAnimation. Must be a valid easing function');
|
|
10347
10232
|
}
|
|
10348
|
-
|
|
10349
|
-
if (config.animationStyle && !['sequential', 'simultaneous'].includes(config.animationStyle)) {
|
|
10350
|
-
errors.push('Invalid animationStyle. Must be "sequential" or "simultaneous"');
|
|
10351
|
-
}
|
|
10352
|
-
|
|
10233
|
+
|
|
10353
10234
|
return {
|
|
10354
10235
|
success: errors.length === 0,
|
|
10355
10236
|
errors
|