@alepot55/chessboardjs 2.3.5 → 2.3.7

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.
@@ -1095,7 +1095,7 @@ var Chessboard = (function (exports) {
1095
1095
  ratio: 0.9,
1096
1096
  piecesPath: '../assets/themes/default',
1097
1097
  animationStyle: 'simultaneous',
1098
- simultaneousAnimationDelay: 100,
1098
+ simultaneousAnimationDelay: 0,
1099
1099
  onMove: () => true,
1100
1100
  onMoveEnd: () => true,
1101
1101
  onChange: () => true,
@@ -1129,19 +1129,19 @@ var Chessboard = (function (exports) {
1129
1129
  constructor(settings = {}) {
1130
1130
  // Initialize validation service
1131
1131
  this._validationService = new ValidationService();
1132
-
1132
+
1133
1133
  // Validate input
1134
1134
  this._validateInput(settings);
1135
-
1135
+
1136
1136
  // Merge with defaults
1137
1137
  const config = this._mergeWithDefaults(settings);
1138
-
1138
+
1139
1139
  // Process and validate configuration
1140
1140
  this._processConfiguration(config);
1141
-
1141
+
1142
1142
  // Set CSS properties
1143
1143
  this._setCSSProperties(config);
1144
-
1144
+
1145
1145
  // Configure mode-specific settings
1146
1146
  this._configureModeSettings();
1147
1147
  }
@@ -1156,7 +1156,7 @@ var Chessboard = (function (exports) {
1156
1156
  if (settings !== null && typeof settings !== 'object') {
1157
1157
  throw new ConfigurationError('Settings must be an object', 'settings', settings);
1158
1158
  }
1159
-
1159
+
1160
1160
  // Validate using validation service
1161
1161
  try {
1162
1162
  this._validationService.validateConfig(settings);
@@ -1190,7 +1190,7 @@ var Chessboard = (function (exports) {
1190
1190
  this.size = config.size;
1191
1191
  this.movableColors = config.movableColors;
1192
1192
  this.piecesPath = config.piecesPath;
1193
-
1193
+
1194
1194
  // Event handlers
1195
1195
  this.onMove = this._validateCallback(config.onMove);
1196
1196
  this.onMoveEnd = this._validateCallback(config.onMoveEnd);
@@ -1218,7 +1218,7 @@ var Chessboard = (function (exports) {
1218
1218
  this.snapbackTime = this._setTime(config.snapbackTime);
1219
1219
  this.dropCenterTime = this._setTime(config.dropCenterTime);
1220
1220
  this.fadeTime = this._setTime(config.fadeTime);
1221
-
1221
+
1222
1222
  // Animation style properties
1223
1223
  this.animationStyle = this._validateAnimationStyle(config.animationStyle);
1224
1224
  this.simultaneousAnimationDelay = this._validateDelay(config.simultaneousAnimationDelay);
@@ -1351,11 +1351,11 @@ var Chessboard = (function (exports) {
1351
1351
  }
1352
1352
  return value;
1353
1353
  }
1354
-
1354
+
1355
1355
  if (typeof value === 'string' && value in ANIMATION_TIMES) {
1356
1356
  return ANIMATION_TIMES[value];
1357
1357
  }
1358
-
1358
+
1359
1359
  throw new ConfigurationError('Invalid time value', 'time', value);
1360
1360
  }
1361
1361
 
@@ -1370,11 +1370,11 @@ var Chessboard = (function (exports) {
1370
1370
  if (typeof value === 'boolean') {
1371
1371
  return value;
1372
1372
  }
1373
-
1373
+
1374
1374
  if (value in BOOLEAN_VALUES) {
1375
1375
  return BOOLEAN_VALUES[value];
1376
1376
  }
1377
-
1377
+
1378
1378
  throw new ConfigurationError('Invalid boolean value', 'boolean', value);
1379
1379
  }
1380
1380
 
@@ -1390,17 +1390,17 @@ var Chessboard = (function (exports) {
1390
1390
  if (typeof value === 'boolean') {
1391
1391
  return value ? TRANSITION_FUNCTIONS.ease : null;
1392
1392
  }
1393
-
1393
+
1394
1394
  // Handle string values
1395
1395
  if (typeof value === 'string' && value in TRANSITION_FUNCTIONS) {
1396
1396
  return TRANSITION_FUNCTIONS[value];
1397
1397
  }
1398
-
1398
+
1399
1399
  // Handle null/undefined
1400
1400
  if (value === null || value === undefined) {
1401
1401
  return null;
1402
1402
  }
1403
-
1403
+
1404
1404
  throw new ConfigurationError('Invalid transition function', 'transitionFunction', value);
1405
1405
  }
1406
1406
 
@@ -1453,7 +1453,7 @@ var Chessboard = (function (exports) {
1453
1453
 
1454
1454
  // Apply updates
1455
1455
  const newConfig = Object.assign({}, this.toObject(), updates);
1456
-
1456
+
1457
1457
  // Re-process configuration
1458
1458
  this._processConfiguration(newConfig);
1459
1459
  this._setCSSProperties(newConfig);
@@ -1676,10 +1676,22 @@ var Chessboard = (function (exports) {
1676
1676
 
1677
1677
  setDrag(f) {
1678
1678
  if (!this.element) { console.debug(`[Piece] setDrag: ${this.id} - element is null`); return; }
1679
+ // Remove previous handlers
1680
+ this.element.onmousedown = null;
1681
+ this.element.ontouchstart = null;
1682
+ this.element.ondragstart = null;
1683
+ if (window.PointerEvent) {
1684
+ this.element.onpointerdown = null;
1685
+ }
1686
+ // Set new handlers
1679
1687
  this.element.ondragstart = (e) => { e.preventDefault(); };
1680
1688
  this.element.onmousedown = f;
1681
1689
  this.element.ontouchstart = f; // Drag touch
1682
- console.debug(`[Piece] setDrag: ${this.id}`);
1690
+ if (window.PointerEvent) {
1691
+ this.element.onpointerdown = f;
1692
+ console.debug(`[Piece] setDrag: pointerdown set for ${this.id}`);
1693
+ }
1694
+ console.debug(`[Piece] setDrag: mousedown/ontouchstart set for ${this.id}`);
1683
1695
  }
1684
1696
 
1685
1697
  destroy() {
@@ -4654,9 +4666,15 @@ var Chessboard = (function (exports) {
4654
4666
  console.debug(`[PieceService] addPieceOnSquare: ${piece.id} to ${square.id}`);
4655
4667
  square.putPiece(piece);
4656
4668
 
4669
+ // Imposta sempre il drag (touch e mouse)
4657
4670
  if (dragFunction) {
4658
4671
  piece.setDrag(dragFunction(square, piece));
4659
4672
  }
4673
+ // Forza il drag touch se manca (debug/robustezza)
4674
+ if (!piece.element.ontouchstart) {
4675
+ piece.element.ontouchstart = dragFunction ? dragFunction(square, piece) : () => { };
4676
+ console.debug(`[PieceService] Forzato ontouchstart su ${piece.id}`);
4677
+ }
4660
4678
 
4661
4679
  if (fade && this.config.fadeTime > 0) {
4662
4680
  piece.fadeIn(
@@ -4714,8 +4732,8 @@ var Chessboard = (function (exports) {
4714
4732
  */
4715
4733
  movePiece(piece, targetSquare, duration, callback) {
4716
4734
  console.debug(`[PieceService] movePiece: ${piece.id} to ${targetSquare.id}`);
4717
- if (!piece) {
4718
- console.warn('PieceService.movePiece: piece is null, skipping animation');
4735
+ if (!piece || !piece.element) {
4736
+ console.warn(`[PieceService] movePiece: piece or element is null, skipping animation`);
4719
4737
  if (callback) callback();
4720
4738
  return;
4721
4739
  }
@@ -4771,7 +4789,7 @@ var Chessboard = (function (exports) {
4771
4789
  };
4772
4790
 
4773
4791
  // Check if piece is currently being dragged
4774
- const isDragging = move.piece.element.classList.contains('dragging');
4792
+ const isDragging = move.piece.element && move.piece.element.classList.contains('dragging');
4775
4793
 
4776
4794
  if (isDragging) {
4777
4795
  // If piece is being dragged, don't animate - just move it immediately
@@ -7096,7 +7114,7 @@ var Chessboard = (function (exports) {
7096
7114
  * Implements the Facade pattern to provide a unified interface
7097
7115
  * @class
7098
7116
  */
7099
- let Chessboard$1 = class Chessboard {
7117
+ class Chessboard {
7100
7118
  /**
7101
7119
  * Creates a new Chessboard instance
7102
7120
  * @param {Object} config - Configuration object
@@ -7121,8 +7139,6 @@ var Chessboard = (function (exports) {
7121
7139
  } catch (error) {
7122
7140
  this._handleConstructorError(error);
7123
7141
  }
7124
- this._undoneMoves = [];
7125
- this._updateBoardPieces(true, true); // Forza popolamento DOM subito
7126
7142
  }
7127
7143
 
7128
7144
  /**
@@ -7166,31 +7182,6 @@ var Chessboard = (function (exports) {
7166
7182
  }
7167
7183
  }
7168
7184
 
7169
- /**
7170
- * Cleans up any partially initialized resources (safe to call multiple times)
7171
- * @private
7172
- */
7173
- _cleanup() {
7174
- // Remove event listeners if present
7175
- if (this.eventService && typeof this.eventService.removeListeners === 'function') {
7176
- this.eventService.removeListeners();
7177
- }
7178
- // Clear timeouts
7179
- if (this._updateTimeout) {
7180
- clearTimeout(this._updateTimeout);
7181
- this._updateTimeout = null;
7182
- }
7183
- // Null all services
7184
- this.validationService = null;
7185
- this.coordinateService = null;
7186
- this.positionService = null;
7187
- this.boardService = null;
7188
- this.pieceService = null;
7189
- this.animationService = null;
7190
- this.moveService = null;
7191
- this.eventService = null;
7192
- }
7193
-
7194
7185
  /**
7195
7186
  * Initializes all services
7196
7187
  * @private
@@ -7259,23 +7250,8 @@ var Chessboard = (function (exports) {
7259
7250
  /**
7260
7251
  * Builds the board DOM structure
7261
7252
  * @private
7262
- * Best practice: always remove squares (destroy JS/DOM) before clearing the board container.
7263
7253
  */
7264
7254
  _buildBoard() {
7265
- console.log('CHIAMATO: _buildBoard');
7266
- if (this._isUndoRedo) {
7267
- console.log('SKIP _buildBoard per undo/redo');
7268
- return;
7269
- }
7270
- // Forza la pulizia completa del contenitore board (DOM)
7271
- const boardContainer = document.getElementById(this.config.id_div);
7272
- if (boardContainer) boardContainer.innerHTML = '';
7273
- // Force remove all pieces from all squares (no animation, best practice)
7274
- if (this.boardService && this.boardService.squares) {
7275
- Object.values(this.boardService.squares).forEach(sq => sq && sq.forceRemoveAllPieces && sq.forceRemoveAllPieces());
7276
- }
7277
- if (this.boardService && this.boardService.removeSquares) this.boardService.removeSquares();
7278
- if (this.boardService && this.boardService.removeBoard) this.boardService.removeBoard();
7279
7255
  this.boardService.buildBoard();
7280
7256
  }
7281
7257
 
@@ -7284,14 +7260,6 @@ var Chessboard = (function (exports) {
7284
7260
  * @private
7285
7261
  */
7286
7262
  _buildSquares() {
7287
- console.log('CHIAMATO: _buildSquares');
7288
- if (this._isUndoRedo) {
7289
- console.log('SKIP _buildSquares per undo/redo');
7290
- return;
7291
- }
7292
- if (this.boardService && this.boardService.removeSquares) {
7293
- this.boardService.removeSquares();
7294
- }
7295
7263
  this.boardService.buildSquares((row, col) => {
7296
7264
  return this.coordinateService.realCoord(row, col);
7297
7265
  });
@@ -7661,7 +7629,6 @@ var Chessboard = (function (exports) {
7661
7629
  * @param {boolean} [isPositionLoad=false] - Whether this is a position load
7662
7630
  */
7663
7631
  _updateBoardPieces(animation = false, isPositionLoad = false) {
7664
- console.log('CHIAMATO: _updateBoardPieces', { animation, isPositionLoad, isUndoRedo: this._isUndoRedo });
7665
7632
  // Check if services are available
7666
7633
  if (!this.positionService || !this.moveService || !this.eventService) {
7667
7634
  console.log('Cannot update board pieces - services not available');
@@ -7727,48 +7694,35 @@ var Chessboard = (function (exports) {
7727
7694
  * @param {boolean} [isPositionLoad=false] - Whether this is a position load (affects delay)
7728
7695
  */
7729
7696
  _doUpdateBoardPieces(animation = false, isPositionLoad = false) {
7730
- // Blocca update se un drag è in corso
7731
- if (this._isDragging) return;
7732
7697
  // Skip update if we're in the middle of a promotion
7733
7698
  if (this._isPromoting) {
7699
+ console.log('Skipping board update during promotion');
7734
7700
  return;
7735
7701
  }
7702
+
7703
+ // Check if services are available
7736
7704
  if (!this.positionService || !this.positionService.getGame()) {
7705
+ console.log('Cannot update board pieces - position service not available');
7737
7706
  return;
7738
7707
  }
7708
+
7739
7709
  const squares = this.boardService.getAllSquares();
7740
7710
  const gameStateBefore = this.positionService.getGame().fen();
7741
- if (/^8\/8\/8\/8\/8\/8\/8\/8/.test(gameStateBefore)) {
7742
- const boardContainer = document.getElementById(this.config.id_div);
7743
- if (boardContainer) {
7744
- const pieceElements = boardContainer.querySelectorAll('.piece');
7745
- pieceElements.forEach(element => {
7746
- element.remove();
7747
- });
7748
- }
7749
- Object.values(squares).forEach(sq => {
7750
- if (sq && sq.piece) {
7751
- sq.piece = null;
7752
- }
7753
- });
7754
- this._clearVisualState();
7755
- this._addListeners();
7756
- if (this.config.onChange) this.config.onChange(gameStateBefore);
7757
- return;
7758
- }
7711
+
7712
+ console.log('_doUpdateBoardPieces - current FEN:', gameStateBefore);
7713
+ console.log('_doUpdateBoardPieces - animation:', animation, 'style:', this.config.animationStyle, 'isPositionLoad:', isPositionLoad);
7714
+
7715
+ // Determine which animation style to use
7759
7716
  const useSimultaneous = this.config.animationStyle === 'simultaneous';
7717
+ console.log('_doUpdateBoardPieces - useSimultaneous:', useSimultaneous);
7718
+
7760
7719
  if (useSimultaneous) {
7720
+ console.log('Using simultaneous animation');
7761
7721
  this._doSimultaneousUpdate(squares, gameStateBefore, isPositionLoad);
7762
7722
  } else {
7723
+ console.log('Using sequential animation');
7763
7724
  this._doSequentialUpdate(squares, gameStateBefore, animation);
7764
7725
  }
7765
- // Pulizia finale robusta: rimuovi tutti i pezzi orfani dal DOM e dal riferimento JS
7766
- Object.values(this.boardService.getAllSquares()).forEach(square => {
7767
- const expectedPieceId = this.positionService.getGamePieceId(square.id);
7768
- if (!expectedPieceId && typeof square.forceRemoveAllPieces === 'function') {
7769
- square.forceRemoveAllPieces();
7770
- }
7771
- });
7772
7726
  }
7773
7727
 
7774
7728
  /**
@@ -7779,45 +7733,43 @@ var Chessboard = (function (exports) {
7779
7733
  * @param {boolean} animation - Whether to animate
7780
7734
  */
7781
7735
  _doSequentialUpdate(squares, gameStateBefore, animation) {
7782
- // Mappa: squareId -> expectedPieceId
7783
- const expectedMap = {};
7784
- Object.values(squares).forEach(square => {
7785
- expectedMap[square.id] = this.positionService.getGamePieceId(square.id);
7786
- });
7787
-
7736
+ // Update each square sequentially
7788
7737
  Object.values(squares).forEach(square => {
7789
- const expectedPieceId = expectedMap[square.id];
7738
+ const expectedPieceId = this.positionService.getGamePieceId(square.id);
7790
7739
  const currentPiece = square.piece;
7791
7740
  const currentPieceId = currentPiece ? currentPiece.getId() : null;
7792
7741
 
7793
- // Se il pezzo attuale e quello atteso sono identici, non fare nulla
7794
- if (currentPieceId === expectedPieceId) {
7795
- return;
7796
- }
7742
+ // Log only for squares that are changing
7743
+ if (currentPieceId !== expectedPieceId) {
7744
+ console.log(`_doSequentialUpdate - ${square.id}: ${currentPieceId} -> ${expectedPieceId}`);
7797
7745
 
7798
- // Se c'è un pezzo attuale ma non è quello atteso, rimuovilo
7799
- if (currentPiece && currentPieceId !== expectedPieceId) {
7800
- // Rimozione robusta: elimina tutti i pezzi orfani dal DOM e dal riferimento JS
7801
- if (typeof square.forceRemoveAllPieces === 'function') {
7802
- square.forceRemoveAllPieces();
7746
+ // Check if we already have the correct piece (from promotion)
7747
+ if (currentPiece && currentPiece.getId() === expectedPieceId) {
7748
+ console.log(`Piece ${expectedPieceId} already correctly placed on ${square.id}`);
7803
7749
  } else {
7804
- this.pieceService.removePieceFromSquare(square, animation);
7805
- }
7806
- }
7750
+ // Remove current piece if exists
7751
+ if (currentPiece) {
7752
+ this.pieceService.removePieceFromSquare(square, animation);
7753
+ }
7807
7754
 
7808
- // Se c'è un pezzo atteso ma non è quello attuale, aggiungilo
7809
- if (expectedPieceId && currentPieceId !== expectedPieceId) {
7810
- const newPiece = this.pieceService.convertPiece(expectedPieceId);
7811
- this.pieceService.addPieceOnSquare(
7812
- square,
7813
- newPiece,
7814
- animation,
7815
- this._createDragFunction.bind(this)
7816
- );
7755
+ // Add new piece if needed
7756
+ if (expectedPieceId) {
7757
+ const newPiece = this.pieceService.convertPiece(expectedPieceId);
7758
+ this.pieceService.addPieceOnSquare(
7759
+ square,
7760
+ newPiece,
7761
+ animation,
7762
+ this._createDragFunction.bind(this)
7763
+ );
7764
+ }
7765
+ }
7817
7766
  }
7818
7767
  });
7819
7768
 
7769
+ // Re-add listeners after updating pieces to ensure hover events work correctly
7820
7770
  this._addListeners();
7771
+
7772
+ // Trigger change event if position changed
7821
7773
  const gameStateAfter = this.positionService.getGame().fen();
7822
7774
  if (gameStateBefore !== gameStateAfter) {
7823
7775
  this.config.onChange(gameStateAfter);
@@ -7832,38 +7784,16 @@ var Chessboard = (function (exports) {
7832
7784
  * @param {boolean} [isPositionLoad=false] - Whether this is a position load
7833
7785
  */
7834
7786
  _doSimultaneousUpdate(squares, gameStateBefore, isPositionLoad = false) {
7835
- // Matching greedy per distanza minima, robusto
7836
- const currentMap = {};
7837
- const expectedMap = {};
7838
-
7839
- Object.values(squares).forEach(square => {
7840
- const currentPiece = square.piece;
7841
- const expectedPieceId = this.positionService.getGamePieceId(square.id);
7842
- if (currentPiece) {
7843
- // Normalizza la chiave come 'color+type' lowercase
7844
- const key = (currentPiece.color + currentPiece.type).toLowerCase();
7845
- if (!currentMap[key]) currentMap[key] = [];
7846
- currentMap[key].push({ square, id: square.id });
7847
- }
7848
- if (expectedPieceId) {
7849
- // Normalizza la chiave come 'color+type' lowercase
7850
- const key = expectedPieceId.toLowerCase();
7851
- if (!expectedMap[key]) expectedMap[key] = [];
7852
- expectedMap[key].push({ square, id: square.id });
7853
- }
7854
- });
7787
+ console.log('_doSimultaneousUpdate - Starting simultaneous update');
7855
7788
 
7856
- let animationsCompleted = 0;
7857
- let totalAnimations = 0;
7858
- const animationDelay = isPositionLoad ? 0 : this.config.simultaneousAnimationDelay;
7859
- let animationIndex = 0;
7789
+ // Analyze what changes need to be made
7790
+ const changeAnalysis = this._analyzePositionChanges(squares);
7860
7791
 
7861
- Object.keys(expectedMap).forEach(key => {
7862
- totalAnimations += Math.max((currentMap[key] || []).length, expectedMap[key].length);
7863
- });
7864
-
7865
- if (totalAnimations === 0) {
7792
+ if (changeAnalysis.totalChanges === 0) {
7793
+ console.log('_doSimultaneousUpdate - No changes needed, returning');
7866
7794
  this._addListeners();
7795
+
7796
+ // Trigger change event if position changed
7867
7797
  const gameStateAfter = this.positionService.getGame().fen();
7868
7798
  if (gameStateBefore !== gameStateAfter) {
7869
7799
  this.config.onChange(gameStateAfter);
@@ -7871,109 +7801,10 @@ var Chessboard = (function (exports) {
7871
7801
  return;
7872
7802
  }
7873
7803
 
7874
- const onAnimationComplete = () => {
7875
- animationsCompleted++;
7876
- if (animationsCompleted === totalAnimations) {
7877
- this._addListeners();
7878
- const gameStateAfter = this.positionService.getGame().fen();
7879
- if (gameStateBefore !== gameStateAfter) {
7880
- this.config.onChange(gameStateAfter);
7881
- }
7882
- }
7883
- };
7884
-
7885
- Object.keys(expectedMap).forEach(key => {
7886
- const fromList = (currentMap[key] || []).slice();
7887
- const toList = expectedMap[key].slice();
7888
-
7889
- // 1. Costruisci matrice delle distanze
7890
- const distances = [];
7891
- for (let i = 0; i < fromList.length; i++) {
7892
- distances[i] = [];
7893
- for (let j = 0; j < toList.length; j++) {
7894
- distances[i][j] = Math.abs(fromList[i].square.row - toList[j].square.row) +
7895
- Math.abs(fromList[i].square.col - toList[j].square.col);
7896
- }
7897
- }
7898
-
7899
- // 2. Matching greedy: abbina i più vicini
7900
- const fromMatched = new Array(fromList.length).fill(false);
7901
- const toMatched = new Array(toList.length).fill(false);
7902
- const moves = [];
7903
-
7904
- while (true) {
7905
- let minDist = Infinity, minI = -1, minJ = -1;
7906
- for (let i = 0; i < fromList.length; i++) {
7907
- if (fromMatched[i]) continue;
7908
- for (let j = 0; j < toList.length; j++) {
7909
- if (toMatched[j]) continue;
7910
- if (distances[i][j] < minDist) {
7911
- minDist = distances[i][j];
7912
- minI = i;
7913
- minJ = j;
7914
- }
7915
- }
7916
- }
7917
- if (minI === -1 || minJ === -1) break;
7918
- // Se la posizione è la stessa, non fare nulla (pezzo unchanged)
7919
- if (fromList[minI].square === toList[minJ].square) {
7920
- fromMatched[minI] = true;
7921
- toMatched[minJ] = true;
7922
- continue;
7923
- }
7924
- // Altrimenti, sposta il pezzo
7925
- moves.push({ from: fromList[minI].square, to: toList[minJ].square, piece: fromList[minI].square.piece });
7926
- fromMatched[minI] = true;
7927
- toMatched[minJ] = true;
7928
- }
7929
-
7930
- // 3. Rimuovi i pezzi non abbinati (presenti solo in fromList)
7931
- for (let i = 0; i < fromList.length; i++) {
7932
- if (!fromMatched[i]) {
7933
- setTimeout(() => {
7934
- // Rimozione robusta: elimina tutti i pezzi orfani dal DOM e dal riferimento JS
7935
- if (typeof fromList[i].square.forceRemoveAllPieces === 'function') {
7936
- fromList[i].square.forceRemoveAllPieces();
7937
- } else {
7938
- this.pieceService.removePieceFromSquare(fromList[i].square, true, onAnimationComplete);
7939
- }
7940
- onAnimationComplete();
7941
- }, animationIndex * animationDelay);
7942
- animationIndex++;
7943
- }
7944
- }
7945
-
7946
- // 4. Aggiungi i pezzi non abbinati (presenti solo in toList)
7947
- for (let j = 0; j < toList.length; j++) {
7948
- if (!toMatched[j]) {
7949
- setTimeout(() => {
7950
- const newPiece = this.pieceService.convertPiece(key);
7951
- this.pieceService.addPieceOnSquare(
7952
- toList[j].square,
7953
- newPiece,
7954
- true,
7955
- this._createDragFunction.bind(this),
7956
- onAnimationComplete
7957
- );
7958
- }, animationIndex * animationDelay);
7959
- animationIndex++;
7960
- }
7961
- }
7804
+ console.log('_doSimultaneousUpdate - Change analysis:', changeAnalysis);
7962
7805
 
7963
- // 5. Anima i movimenti
7964
- moves.forEach(move => {
7965
- setTimeout(() => {
7966
- this.pieceService.translatePiece(
7967
- move,
7968
- false,
7969
- true,
7970
- this._createDragFunction.bind(this),
7971
- onAnimationComplete
7972
- );
7973
- }, animationIndex * animationDelay);
7974
- animationIndex++;
7975
- });
7976
- });
7806
+ // Execute all changes simultaneously
7807
+ this._executeSimultaneousChanges(changeAnalysis, gameStateBefore, isPositionLoad);
7977
7808
  }
7978
7809
 
7979
7810
  /**
@@ -8299,380 +8130,99 @@ var Chessboard = (function (exports) {
8299
8130
  }
8300
8131
 
8301
8132
  // -------------------
8302
- // Public API Methods (Refactored)
8133
+ // Public API Methods
8303
8134
  // -------------------
8304
8135
 
8305
- // --- POSITION & STATE ---
8306
8136
  /**
8307
- * Get the current position as FEN
8308
- * @returns {string}
8309
- */
8310
- getPosition() { return this.fen(); }
8311
- /**
8312
- * Set the board position (FEN or object)
8313
- * @param {string|Object} position
8314
- * @param {Object} [opts]
8315
- * @param {boolean} [opts.animate=true]
8316
- * @returns {boolean}
8317
- */
8318
- setPosition(position, opts = {}) {
8319
- const animate = opts.animate !== undefined ? opts.animate : true;
8320
- // Remove highlights and selections
8321
- if (this.boardService && this.boardService.applyToAllSquares) {
8322
- this.boardService.applyToAllSquares('removeHint');
8323
- this.boardService.applyToAllSquares('deselect');
8324
- this.boardService.applyToAllSquares('unmoved');
8325
- }
8326
- if (this.positionService && this.positionService.setGame) {
8327
- this.positionService.setGame(position);
8328
- }
8329
- if (this._updateBoardPieces) {
8330
- this._updateBoardPieces(animate, true);
8331
- }
8332
- // Forza la sincronizzazione dopo setPosition
8333
- this._updateBoardPieces(true, false);
8334
- return true;
8335
- }
8336
- /**
8337
- * Reset the board to the starting position
8338
- * @param {Object} [opts]
8339
- * @param {boolean} [opts.animate=true]
8340
- * @returns {boolean}
8341
- */
8342
- reset(opts = {}) {
8343
- const animate = opts.animate !== undefined ? opts.animate : true;
8344
- // Use the default starting position from config or fallback
8345
- const startPosition = this.config && this.config.position ? this.config.position : 'start';
8346
- this._updateBoardPieces(animate);
8347
- const result = this.setPosition(startPosition, { animate });
8348
- // Forza la sincronizzazione dopo reset
8349
- this._updateBoardPieces(true, false);
8350
- return result;
8351
- }
8352
- /**
8353
- * Clear the board
8354
- * @param {Object} [opts]
8355
- * @param {boolean} [opts.animate=true]
8356
- * @returns {boolean}
8137
+ * Gets the current position as FEN
8138
+ * @returns {string} FEN string
8357
8139
  */
8358
- clear(opts = {}) {
8359
- const animate = opts.animate !== undefined ? opts.animate : true;
8360
- if (!this.positionService || !this.positionService.getGame()) {
8361
- return false;
8362
- }
8363
- if (this._clearVisualState) this._clearVisualState();
8364
- this.positionService.getGame().clear();
8365
- // Forza la rimozione di tutti i pezzi dal DOM
8366
- if (this.boardService && this.boardService.squares) {
8367
- Object.values(this.boardService.squares).forEach(sq => {
8368
- if (sq && sq.piece) sq.piece = null;
8369
- });
8370
- }
8371
- if (this._updateBoardPieces) {
8372
- this._updateBoardPieces(animate, true);
8373
- }
8374
- // Forza la sincronizzazione dopo clear
8375
- this._updateBoardPieces(true, false);
8376
- return true;
8140
+ fen() {
8141
+ return this.positionService.getGame().fen();
8377
8142
  }
8378
8143
 
8379
- // --- MOVE MANAGEMENT ---
8380
8144
  /**
8381
- * Undo last move
8382
- * @param {Object} [opts]
8383
- * @param {boolean} [opts.animate=true]
8384
- * @returns {boolean}
8145
+ * Gets current turn
8146
+ * @returns {string} 'w' or 'b'
8385
8147
  */
8386
- undoMove(opts = {}) {
8387
- const undone = this.positionService.getGame().undo();
8388
- if (undone) {
8389
- this._undoneMoves.push(undone);
8390
- // Forza refresh completo di tutti i pezzi dopo undo
8391
- this._updateBoardPieces(true, true);
8392
- return undone;
8393
- }
8394
- return null;
8395
- }
8396
- /**
8397
- * Redo last undone move
8398
- * @param {Object} [opts]
8399
- * @param {boolean} [opts.animate=true]
8400
- * @returns {boolean}
8401
- */
8402
- redoMove(opts = {}) {
8403
- if (this._undoneMoves && this._undoneMoves.length > 0) {
8404
- const move = this._undoneMoves.pop();
8405
- const moveObj = { from: move.from, to: move.to };
8406
- if (move.promotion) moveObj.promotion = move.promotion;
8407
- const result = this.positionService.getGame().move(moveObj);
8408
- // Forza refresh completo di tutti i pezzi dopo redo
8409
- this._updateBoardPieces(true, true);
8410
- return result;
8411
- }
8412
- return false;
8148
+ turn() {
8149
+ return this.positionService.getGame().turn();
8413
8150
  }
8414
- /**
8415
- * Get legal moves for a square
8416
- * @param {string} square
8417
- * @returns {Array}
8418
- */
8419
- getLegalMoves(square) { return this.legalMoves(square); }
8420
8151
 
8421
- // --- PIECE MANAGEMENT ---
8422
8152
  /**
8423
- * Get the piece at a square
8424
- * @param {string} square
8425
- * @returns {string|null}
8426
- */
8427
- getPiece(square) {
8428
- // Sempre leggi lo stato aggiornato dal boardService
8429
- const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
8430
- if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[getPiece] Parametro square non valido');
8431
- // Forza sync prima di leggere
8432
- this._updateBoardPieces(false, false);
8433
- const piece = squareObj.piece;
8434
- if (!piece) return null;
8435
- return (piece.color + piece.type).toLowerCase();
8436
- }
8437
- /**
8438
- * Put a piece on a square
8439
- * @param {string|Piece} piece
8440
- * @param {string|Square} square
8441
- * @param {Object} [opts]
8442
- * @param {boolean} [opts.animate=true]
8443
- * @returns {boolean}
8153
+ * Loads a new position
8154
+ * @param {string|Object} position - Position to load
8155
+ * @param {Object} [options={}] - Loading options
8156
+ * @param {boolean} [animation=true] - Whether to animate
8444
8157
  */
8445
- putPiece(piece, square, opts = {}) {
8446
- const animate = opts.animate !== undefined ? opts.animate : true;
8447
- let pieceStr = piece;
8448
- if (typeof piece === 'object' && piece.type && piece.color) {
8449
- pieceStr = (piece.color + piece.type).toLowerCase();
8450
- } else if (typeof piece === 'string' && piece.length === 2) {
8451
- const a = piece[0].toLowerCase();
8452
- const b = piece[1].toLowerCase();
8453
- const types = 'kqrbnp';
8454
- const colors = 'wb';
8455
- if (types.includes(a) && colors.includes(b)) {
8456
- pieceStr = b + a;
8457
- } else if (colors.includes(a) && types.includes(b)) {
8458
- pieceStr = a + b;
8459
- } else {
8460
- throw new Error(`[putPiece] Invalid piece: ${piece}`);
8461
- }
8462
- }
8463
- const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
8464
- if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[putPiece] Parametro square non valido');
8465
- const pieceObj = this.pieceService.convertPiece(pieceStr);
8466
- if (!pieceObj || typeof pieceObj !== 'object' || !('type' in pieceObj)) throw new Error('[putPiece] Parametro piece non valido');
8467
- // Aggiorna solo il motore chess.js
8468
- const chessJsPiece = { type: pieceObj.type, color: pieceObj.color };
8469
- const game = this.positionService.getGame();
8470
- const result = game.put(chessJsPiece, squareObj.id);
8471
- if (!result) throw new Error(`[putPiece] Game.put failed for ${pieceStr} on ${squareObj.id}`);
8472
- // Non aggiornare direttamente square.piece!
8473
- // Riallinea la board JS allo stato del motore
8474
- this._updateBoardPieces(animate);
8475
- return true;
8476
- }
8477
- /**
8478
- * Remove a piece from a square
8479
- * @param {string|Square} square
8480
- * @param {Object} [opts]
8481
- * @param {boolean} [opts.animate=true]
8482
- * @returns {string|null}
8483
- */
8484
- removePiece(square, opts = {}) {
8485
- const animate = opts.animate !== undefined ? opts.animate : true;
8486
- const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
8487
- if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[removePiece] Parametro square non valido');
8488
- // Aggiorna solo il motore chess.js
8489
- const game = this.positionService.getGame();
8490
- game.remove(squareObj.id);
8491
- // Non aggiornare direttamente square.piece!
8492
- // Riallinea la board JS allo stato del motore
8493
- this._updateBoardPieces(animate);
8494
- return true;
8495
- }
8158
+ load(position, options = {}, animation = true) {
8159
+ this.boardService.applyToAllSquares('removeHint');
8160
+ this.boardService.applyToAllSquares('deselect');
8161
+ this.boardService.applyToAllSquares('unmoved');
8496
8162
 
8497
- // --- BOARD CONTROL ---
8498
- /**
8499
- * Flip the board orientation
8500
- * @param {Object} [opts]
8501
- * @param {boolean} [opts.animate=true]
8502
- */
8503
- flipBoard(opts = {}) {
8504
- if (this.coordinateService && this.coordinateService.flipOrientation) {
8505
- this.coordinateService.flipOrientation();
8506
- }
8507
- if (this._buildBoard) this._buildBoard();
8508
- if (this._buildSquares) this._buildSquares();
8509
- if (this._addListeners) this._addListeners();
8510
- if (this._updateBoardPieces) this._updateBoardPieces(opts.animate !== false);
8511
- console.log('FEN dopo flip:', this.fen(), 'Orientamento:', this.coordinateService.getOrientation());
8512
- }
8513
- /**
8514
- * Set the board orientation
8515
- * @param {'w'|'b'} color
8516
- * @param {Object} [opts]
8517
- * @param {boolean} [opts.animate=true]
8518
- */
8519
- setOrientation(color, opts = {}) {
8520
- if (this.validationService.isValidOrientation(color)) {
8521
- this.coordinateService.setOrientation(color);
8522
- if (this._buildBoard) this._buildBoard();
8523
- if (this._buildSquares) this._buildSquares();
8524
- if (this._addListeners) this._addListeners();
8525
- if (this._updateBoardPieces) this._updateBoardPieces(opts.animate !== false);
8526
- }
8527
- return this.coordinateService.getOrientation();
8528
- }
8529
- /**
8530
- * Get the current orientation
8531
- * @returns {'w'|'b'}
8532
- */
8533
- getOrientation() { return this.orientation(); }
8534
- /**
8535
- * Resize the board
8536
- * @param {number|string} size
8537
- */
8538
- resizeBoard(size) {
8539
- if (size === 'auto') {
8540
- this.config.size = 'auto';
8541
- document.documentElement.style.setProperty('--dimBoard', 'auto');
8542
- this._updateBoardPieces(false);
8543
- return true;
8544
- }
8545
- if (typeof size !== 'number' || size < 50 || size > 3000) {
8546
- throw new Error(`[resizeBoard] Invalid size: ${size}`);
8547
- }
8548
- this.config.size = size;
8549
- document.documentElement.style.setProperty('--dimBoard', `${size}px`);
8550
- this._updateBoardPieces(false);
8551
- return true;
8163
+ this.positionService.setGame(position, options);
8164
+ this._updateBoardPieces(animation, true); // Position load
8552
8165
  }
8553
8166
 
8554
- // --- HIGHLIGHTING & UI ---
8555
8167
  /**
8556
- * Highlight a square
8557
- * @param {string|Square} square
8558
- * @param {Object} [opts]
8168
+ * Destroys the board and cleans up resources
8559
8169
  */
8560
- highlight(square, opts = {}) {
8561
- // API: accetta id, converte subito in oggetto
8562
- const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
8563
- if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[highlight] Parametro square non valido');
8564
- if (this.boardService && this.boardService.highlightSquare) {
8565
- this.boardService.highlightSquare(squareObj, opts);
8566
- } else if (this.eventService && this.eventService.highlightSquare) {
8567
- this.eventService.highlightSquare(squareObj, opts);
8568
- }
8569
- }
8570
- /**
8571
- * Remove highlight from a square
8572
- * @param {string|Square} square
8573
- * @param {Object} [opts]
8574
- */
8575
- dehighlight(square, opts = {}) {
8576
- // API: accetta id, converte subito in oggetto
8577
- const squareObj = typeof square === 'string' ? this.boardService.getSquare(square) : square;
8578
- if (!squareObj || typeof squareObj !== 'object' || !('id' in squareObj)) throw new Error('[dehighlight] Parametro square non valido');
8579
- if (this.boardService && this.boardService.dehighlightSquare) {
8580
- this.boardService.dehighlightSquare(squareObj, opts);
8581
- } else if (this.eventService && this.eventService.dehighlightSquare) {
8582
- this.eventService.dehighlightSquare(squareObj, opts);
8170
+ destroy() {
8171
+ this.eventService.destroy();
8172
+ this.boardService.destroy();
8173
+ this.positionService.destroy();
8174
+ this.pieceService.destroy();
8175
+ this.moveService.destroy();
8176
+ this.animationService.destroy();
8177
+ this.validationService.destroy();
8178
+
8179
+ if (this._updateTimeout) {
8180
+ clearTimeout(this._updateTimeout);
8181
+ this._updateTimeout = null;
8583
8182
  }
8584
8183
  }
8585
8184
 
8586
- // --- GAME INFO ---
8587
- /**
8588
- * Get FEN string
8589
- * @returns {string}
8590
- */
8591
- fen() {
8592
- // Avoid recursion: call the underlying game object's fen()
8593
- const game = this.positionService.getGame();
8594
- if (!game || typeof game.fen !== 'function') return '';
8595
- return game.fen();
8596
- }
8597
8185
  /**
8598
- * Get current turn
8599
- * @returns {'w'|'b'}
8186
+ * Resizes the board
8187
+ * @param {number|string} size - New size
8600
8188
  */
8601
- turn() { return this.positionService.getGame().turn(); }
8602
- /**
8603
- * Is the game over?
8604
- * @returns {boolean}
8605
- */
8606
- isGameOver() {
8607
- // Forza sync prima di interrogare il motore
8608
- this._updateBoardPieces(false, false);
8609
- const game = this.positionService.getGame();
8610
- if (!game) return false;
8611
- if (game.isGameOver) return game.isGameOver();
8612
- // Fallback: checkmate or draw
8613
- if (game.isCheckmate && game.isCheckmate()) return true;
8614
- if (game.isDraw && game.isDraw()) return true;
8615
- return false;
8616
- }
8617
- /**
8618
- * Is it checkmate?
8619
- * @returns {boolean}
8620
- */
8621
- isCheckmate() {
8622
- const game = this.positionService.getGame();
8623
- if (!game) return false;
8624
- return game.isCheckmate ? game.isCheckmate() : false;
8625
- }
8626
- /**
8627
- * Is it draw?
8628
- * @returns {boolean}
8629
- */
8630
- isDraw() {
8631
- const game = this.positionService.getGame();
8632
- if (!game) return false;
8633
- return game.isDraw ? game.isDraw() : false;
8634
- }
8635
- /**
8636
- * Get move history
8637
- * @returns {Array}
8638
- */
8639
- getHistory() {
8640
- const game = this.positionService.getGame();
8641
- if (!game) return [];
8642
- return game.history ? game.history() : [];
8189
+ resize(size) {
8190
+ this.boardService.resize(size);
8191
+ this._updateBoardPieces();
8643
8192
  }
8644
8193
 
8645
- // --- LIFECYCLE ---
8646
8194
  /**
8647
- * Destroy the board and cleanup
8648
- */
8649
- destroy() { /* TODO: robust destroy logic */ }
8650
- /**
8651
- * Rebuild the board
8195
+ * Flips the board orientation
8652
8196
  */
8653
- rebuild() { this._initialize(); }
8197
+ flip() {
8198
+ this.coordinateService.flipOrientation();
8654
8199
 
8655
- // --- CONFIGURATION ---
8656
- /**
8657
- * Get current config
8658
- * @returns {Object}
8659
- */
8660
- getConfig() { return this.config; }
8661
- /**
8662
- * Set new config
8663
- * @param {Object} newConfig
8664
- */
8665
- setConfig(newConfig) { this.setConfig(newConfig); }
8200
+ // Save current position before destroying
8201
+ let currentPosition = null;
8202
+ try {
8203
+ // Check if there are any pieces on the board
8204
+ const position = this.positionService.getPosition();
8205
+ const hasPieces = Object.keys(position).length > 0;
8666
8206
 
8667
- // --- ALIASES/DEPRECATED ---
8668
- // Note: These methods are now implemented as aliases at the end of the class
8207
+ if (hasPieces) {
8208
+ currentPosition = this.positionService.getGame().fen();
8209
+ }
8210
+ } catch (error) {
8211
+ console.log('No valid position to save during flip');
8212
+ }
8669
8213
 
8670
- /**
8671
- * Alias for flipBoard (for backward compatibility)
8672
- */
8673
- flip(opts = {}) {
8674
- this._updateBoardPieces(opts.animate !== false);
8675
- return this.flipBoard(opts);
8214
+ this.destroy();
8215
+ this._initializeServices(); // Recreate all services
8216
+ this._initParams();
8217
+
8218
+ // Restore position after rebuilding if we had one
8219
+ if (currentPosition) {
8220
+ this._setGame(currentPosition);
8221
+ }
8222
+ this._buildBoard();
8223
+ this._buildSquares();
8224
+ this._addListeners();
8225
+ this._updateBoardPieces(true, true);
8676
8226
  }
8677
8227
 
8678
8228
  /**
@@ -8695,19 +8245,51 @@ var Chessboard = (function (exports) {
8695
8245
  this.load(position, {}, animate); // load() already handles isPositionLoad=true
8696
8246
  }
8697
8247
 
8248
+ /**
8249
+ * Makes a move on the board
8250
+ * @param {string|Object} move - Move to make
8251
+ * @param {boolean} [animate=true] - Whether to animate
8252
+ * @returns {boolean} True if move was successful
8253
+ */
8254
+ move(move, animate = true) {
8255
+ if (typeof move === 'string') {
8256
+ // Parse move string (e.g., 'e2e4')
8257
+ const moveObj = this.moveService.parseMove(move);
8258
+ if (!moveObj) return false;
8259
+
8260
+ const fromSquare = this.boardService.getSquare(moveObj.from);
8261
+ const toSquare = this.boardService.getSquare(moveObj.to);
8262
+
8263
+ if (!fromSquare || !toSquare) return false;
8264
+
8265
+ return this._onMove(fromSquare, toSquare, moveObj.promotion, animate);
8266
+ } else if (move && move.from && move.to) {
8267
+ // Handle move object
8268
+ const fromSquare = this.boardService.getSquare(move.from);
8269
+ const toSquare = this.boardService.getSquare(move.to);
8270
+
8271
+ if (!fromSquare || !toSquare) return false;
8272
+
8273
+ return this._onMove(fromSquare, toSquare, move.promotion, animate);
8274
+ }
8275
+
8276
+ return false;
8277
+ }
8278
+
8698
8279
  /**
8699
8280
  * Undoes the last move
8700
8281
  * @param {boolean} [animate=true] - Whether to animate
8701
8282
  * @returns {boolean} True if undo was successful
8702
8283
  */
8703
8284
  undo(animate = true) {
8704
- const undone = this.positionService.getGame().undo();
8705
- if (undone) {
8706
- this._undoneMoves.push(undone);
8707
- this._updateBoardPieces(animate);
8708
- return undone;
8285
+ if (this.positionService.getGame().undo) {
8286
+ const undoResult = this.positionService.getGame().undo();
8287
+ if (undoResult) {
8288
+ this._updateBoardPieces(animate, true); // Position change
8289
+ return true;
8290
+ }
8709
8291
  }
8710
- return null;
8292
+ return false;
8711
8293
  }
8712
8294
 
8713
8295
  /**
@@ -8716,13 +8298,12 @@ var Chessboard = (function (exports) {
8716
8298
  * @returns {boolean} True if redo was successful
8717
8299
  */
8718
8300
  redo(animate = true) {
8719
- if (this._undoneMoves && this._undoneMoves.length > 0) {
8720
- const move = this._undoneMoves.pop();
8721
- const moveObj = { from: move.from, to: move.to };
8722
- if (move.promotion) moveObj.promotion = move.promotion;
8723
- const result = this.positionService.getGame().move(moveObj);
8724
- this._updateBoardPieces(animate);
8725
- return result;
8301
+ if (this.positionService.getGame().redo) {
8302
+ const redoResult = this.positionService.getGame().redo();
8303
+ if (redoResult) {
8304
+ this._updateBoardPieces(animate, true); // Position change
8305
+ return true;
8306
+ }
8726
8307
  }
8727
8308
  return false;
8728
8309
  }
@@ -8884,6 +8465,112 @@ var Chessboard = (function (exports) {
8884
8465
  }
8885
8466
  }
8886
8467
 
8468
+ /**
8469
+ * Clears the board
8470
+ * @param {boolean} [animate=true] - Whether to animate
8471
+ */
8472
+ clear(animate = true) {
8473
+ // Check if services are available
8474
+ if (!this.positionService || !this.positionService.getGame()) {
8475
+ console.log('Cannot clear - position service not available');
8476
+ return;
8477
+ }
8478
+
8479
+ // Clear visual state first
8480
+ this._clearVisualState();
8481
+
8482
+ // Clear game state
8483
+ this.positionService.getGame().clear();
8484
+
8485
+ // Update board visually
8486
+ this._updateBoardPieces(animate, true); // Position change
8487
+ }
8488
+
8489
+ /**
8490
+ * Resets the board to starting position
8491
+ * @param {boolean} [animate=true] - Whether to animate
8492
+ */
8493
+ reset(animate = true) {
8494
+ // Check if services are available
8495
+ if (!this.positionService || !this.positionService.getGame()) {
8496
+ console.log('Cannot reset - position service not available');
8497
+ return;
8498
+ }
8499
+
8500
+ this.positionService.getGame().reset();
8501
+ this._updateBoardPieces(animate, true); // Position change
8502
+ }
8503
+
8504
+ /**
8505
+ * Puts a piece on a square
8506
+ * @param {string} square - Square to put piece on
8507
+ * @param {string} piece - Piece to put
8508
+ * @param {boolean} [animate=true] - Whether to animate
8509
+ * @returns {boolean} True if successful
8510
+ */
8511
+ put(square, piece, animate = true) {
8512
+ console.log(`put() called with square: ${square}, piece: ${piece}`);
8513
+
8514
+ if (!this.validationService.isValidSquare(square) || !this.validationService.isValidPiece(piece)) {
8515
+ console.log('Validation failed');
8516
+ return false;
8517
+ }
8518
+
8519
+ // Check if services are available
8520
+ if (!this.positionService || !this.positionService.getGame()) {
8521
+ console.log('Cannot put piece - position service not available');
8522
+ return false;
8523
+ }
8524
+
8525
+ const pieceObj = this.pieceService.convertPiece(piece);
8526
+ console.log(`Converted piece:`, pieceObj);
8527
+ console.log(`Piece type: ${pieceObj.type}, color: ${pieceObj.color}`);
8528
+
8529
+ const squareObj = this.boardService.getSquare(square);
8530
+
8531
+ if (!squareObj) {
8532
+ console.log('Square not found');
8533
+ return false;
8534
+ }
8535
+
8536
+ // Update game state - note: chess.js expects (piece, square) order
8537
+ const chessJsPiece = { type: pieceObj.type.toLowerCase(), color: pieceObj.color.toLowerCase() };
8538
+ console.log(`Chess.js piece:`, chessJsPiece);
8539
+
8540
+ const result = this.positionService.getGame().put(chessJsPiece, square);
8541
+ console.log(`Chess.js put result:`, result);
8542
+
8543
+ if (result) {
8544
+ // Update visual representation
8545
+ this._updateBoardPieces(animate, true); // Position change
8546
+ }
8547
+
8548
+ return result;
8549
+ }
8550
+
8551
+ /**
8552
+ * Removes a piece from a square
8553
+ * @param {string} square - Square to remove piece from
8554
+ * @param {boolean} [animate=true] - Whether to animate
8555
+ * @returns {boolean} True if successful
8556
+ */
8557
+ remove(square, animate = true) {
8558
+ if (!this.validationService.isValidSquare(square)) {
8559
+ return false;
8560
+ }
8561
+
8562
+ const squareObj = this.boardService.getSquare(square);
8563
+ if (!squareObj) return false;
8564
+
8565
+ // Update game state
8566
+ this.positionService.getGame().remove(square);
8567
+
8568
+ // Update visual representation
8569
+ this._updateBoardPieces(animate, true); // Position change
8570
+
8571
+ return true;
8572
+ }
8573
+
8887
8574
  /**
8888
8575
  * Gets configuration options
8889
8576
  * @returns {Object} Configuration object
@@ -8945,97 +8632,7 @@ var Chessboard = (function (exports) {
8945
8632
 
8946
8633
  // Additional API methods would be added here following the same pattern
8947
8634
  // This is a good starting point for the refactored architecture
8948
-
8949
- // Additional API methods and aliases for backward compatibility
8950
- insert(square, piece) { return this.putPiece(piece, square); }
8951
- build() { return this._initialize(); }
8952
- ascii() { return this.positionService.getGame().ascii(); }
8953
- board() { return this.positionService.getGame().board(); }
8954
- getCastlingRights(color) { return this.positionService.getGame().getCastlingRights(color); }
8955
- getComment() { return this.positionService.getGame().getComment(); }
8956
- getComments() { return this.positionService.getGame().getComments(); }
8957
- lastMove() { return this.positionService.getGame().lastMove(); }
8958
- moveNumber() { return this.positionService.getGame().moveNumber(); }
8959
- moves(options = {}) { return this.positionService.getGame().moves(options); }
8960
- squareColor(squareId) { return this.boardService.getSquare(squareId).isWhite() ? 'light' : 'dark'; }
8961
- isDrawByFiftyMoves() { return this.positionService.getGame().isDrawByFiftyMoves(); }
8962
- isInsufficientMaterial() { return this.positionService.getGame().isInsufficientMaterial(); }
8963
- removeComment() { return this.positionService.getGame().removeComment(); }
8964
- removeComments() { return this.positionService.getGame().removeComments(); }
8965
- removeHeader(field) { return this.positionService.getGame().removeHeader(field); }
8966
- setCastlingRights(color, rights) { return this.positionService.getGame().setCastlingRights(color, rights); }
8967
- setComment(comment) { return this.positionService.getGame().setComment(comment); }
8968
- setHeader(key, value) { return this.positionService.getGame().setHeader(key, value); }
8969
- validateFen(fen) { return this.positionService.getGame().validateFen(fen); }
8970
-
8971
- // Implementazioni reali per highlight/dehighlight
8972
- highlightSquare(square) {
8973
- return this.boardService.highlight(square);
8974
- }
8975
- dehighlightSquare(square) {
8976
- return this.boardService.dehighlight(square);
8977
- }
8978
- forceSync() { this._updateBoardPieces(true, true); this._updateBoardPieces(true, false); }
8979
-
8980
- // Metodi mancanti che causano fallimenti nei test
8981
- /**
8982
- * Move a piece from one square to another
8983
- * @param {string|Object} move - Move in format 'e2e4' or {from: 'e2', to: 'e4'}
8984
- * @param {Object} [opts] - Options
8985
- * @param {boolean} [opts.animate=true] - Whether to animate
8986
- * @returns {boolean} True if move was successful
8987
- */
8988
- movePiece(move, opts = {}) {
8989
- const animate = opts.animate !== undefined ? opts.animate : true;
8990
-
8991
- // --- API: accetta id/stringhe, ma converte subito in oggetti ---
8992
- let fromSquareObj, toSquareObj, promotion;
8993
- if (typeof move === 'string') {
8994
- if (move.length === 4) {
8995
- fromSquareObj = this.boardService.getSquare(move.substring(0, 2));
8996
- toSquareObj = this.boardService.getSquare(move.substring(2, 4));
8997
- } else if (move.length === 5) {
8998
- fromSquareObj = this.boardService.getSquare(move.substring(0, 2));
8999
- toSquareObj = this.boardService.getSquare(move.substring(2, 4));
9000
- promotion = move.substring(4, 5);
9001
- } else {
9002
- throw new Error(`Invalid move format: ${move}`);
9003
- }
9004
- } else if (typeof move === 'object' && move.from && move.to) {
9005
- // Se sono id, converto in oggetti; se sono già oggetti, li uso direttamente
9006
- fromSquareObj = typeof move.from === 'string' ? this.boardService.getSquare(move.from) : move.from;
9007
- toSquareObj = typeof move.to === 'string' ? this.boardService.getSquare(move.to) : move.to;
9008
- promotion = move.promotion;
9009
- } else {
9010
- throw new Error(`Invalid move: ${move}`);
9011
- }
9012
-
9013
- if (!fromSquareObj || !toSquareObj) {
9014
- throw new Error(`Invalid squares: ${move.from || move.substring(0, 2)} or ${move.to || move.substring(2, 4)}`);
9015
- }
9016
-
9017
- // --- Internamente: lavora solo con oggetti ---
9018
- const result = this._onMove(fromSquareObj, toSquareObj, promotion, animate);
9019
- // Dopo ogni mossa, forza la sincronizzazione della board
9020
- this._updateBoardPieces(true, false);
9021
- return result;
9022
- }
9023
-
9024
- // Aliases for backward compatibility
9025
- move(move, animate = true) {
9026
- // On any new move, clear the redo stack
9027
- this._undoneMoves = [];
9028
- return this.movePiece(move, { animate });
9029
- }
9030
- get(square) { return this.getPiece(square); }
9031
- piece(square) { return this.getPiece(square); }
9032
- put(piece, square, opts = {}) { return this.putPiece(piece, square, opts); }
9033
- remove(square, opts = {}) { return this.removePiece(square, opts); }
9034
- load(position, opts = {}) { return this.setPosition(position, opts); }
9035
- resize(size) { return this.resizeBoard(size); }
9036
- start(opts = {}) { return this.reset(opts); }
9037
- clearBoard(opts = {}) { return this.clear(opts); }
9038
- };
8635
+ }
9039
8636
 
9040
8637
  /**
9041
8638
  * Structured logging system for Chessboard.js
@@ -9582,7 +9179,7 @@ var Chessboard = (function (exports) {
9582
9179
  this.validationService.validateConfig(finalConfig);
9583
9180
 
9584
9181
  // Create chessboard instance
9585
- const chessboard = new Chessboard$1(finalConfig);
9182
+ const chessboard = new Chessboard(finalConfig);
9586
9183
 
9587
9184
  // Store instance for management
9588
9185
  this.instances.set(containerId, {
@@ -9842,44 +9439,13 @@ var Chessboard = (function (exports) {
9842
9439
  */
9843
9440
 
9844
9441
 
9845
- /**
9846
- * Main Chessboard factory function for backward compatibility
9847
- * Supports both legacy and modern calling conventions
9848
- * @param {string|Object} containerElm - Container element ID or configuration object
9849
- * @param {Object} [config={}] - Configuration options (when first param is string)
9850
- * @returns {ChessboardClass} Chessboard instance
9851
- */
9852
- function Chessboard(containerElm, config = {}) {
9853
- const factoryLogger = logger.child('ChessboardFactory');
9854
-
9855
- try {
9856
- // If first parameter is an object, treat it as config
9857
- if (typeof containerElm === 'object' && containerElm !== null) {
9858
- factoryLogger.debug('Creating chessboard with config object');
9859
- return new Chessboard$1(containerElm);
9860
- }
9861
-
9862
- // Otherwise, treat first parameter as element ID
9863
- if (typeof containerElm === 'string') {
9864
- factoryLogger.debug('Creating chessboard with element ID', { elementId: containerElm });
9865
- const fullConfig = { ...config, id: containerElm };
9866
- return new Chessboard$1(fullConfig);
9867
- }
9868
-
9869
- throw new Error('Invalid parameters: first parameter must be string or object');
9870
- } catch (error) {
9871
- factoryLogger.error('Failed to create chessboard instance', { error });
9872
- throw error;
9873
- }
9874
- }
9875
-
9876
9442
  /**
9877
9443
  * Wrapper class that handles both calling conventions
9878
9444
  * Provides enhanced error handling and logging
9879
9445
  * @class
9880
9446
  * @extends ChessboardClass
9881
9447
  */
9882
- class ChessboardWrapper extends Chessboard$1 {
9448
+ class ChessboardWrapper extends Chessboard {
9883
9449
  /**
9884
9450
  * Creates a new ChessboardWrapper instance
9885
9451
  * @param {string|Object} containerElm - Container element ID or configuration object
@@ -9908,53 +9474,32 @@ var Chessboard = (function (exports) {
9908
9474
  }
9909
9475
  }
9910
9476
 
9911
- /**
9912
- * Refactored Chessboard API - see Chessboard.js for full method docs
9913
- * @typedef {import('./Chessboard.js').Chessboard} Chessboard
9914
- */
9477
+ // Attach classes and utilities to the factory function for direct access
9478
+ Chessboard.Class = ChessboardWrapper;
9479
+ Chessboard.Chessboard = ChessboardWrapper;
9480
+ Chessboard.Config = ChessboardConfig;
9481
+ Chessboard.Factory = ChessboardFactory;
9915
9482
 
9916
- // --- STATIC/FACTORY METHODS ---
9917
- /**
9918
- * Create a new Chessboard instance
9919
- * @param {string|Object} containerElm
9920
- * @param {Object} [config]
9921
- * @returns {Chessboard}
9922
- */
9483
+ // Attach factory methods
9923
9484
  Chessboard.create = createChessboard;
9924
- /**
9925
- * Create a Chessboard from a template
9926
- * @param {string|Object} containerElm
9927
- * @param {string} templateName
9928
- * @param {Object} [config]
9929
- * @returns {Chessboard}
9930
- */
9931
- Chessboard.fromTemplate = createChessboardFromTemplate;
9485
+ Chessboard.createFromTemplate = createChessboardFromTemplate;
9932
9486
  Chessboard.factory = chessboardFactory;
9933
9487
 
9934
- // --- INSTANCE MANAGEMENT ---
9488
+ // Static methods for instance management
9935
9489
  Chessboard.getInstance = (containerId) => chessboardFactory.getInstance(containerId);
9936
9490
  Chessboard.destroyInstance = (containerId) => chessboardFactory.destroy(containerId);
9937
9491
  Chessboard.destroyAll = () => chessboardFactory.destroyAll();
9938
9492
  Chessboard.listInstances = () => chessboardFactory.listInstances();
9939
9493
 
9940
- // --- TEMPLATE MANAGEMENT ---
9494
+ // Template management
9941
9495
  Chessboard.registerTemplate = (name, config) => chessboardFactory.registerTemplate(name, config);
9942
9496
  Chessboard.removeTemplate = (name) => chessboardFactory.removeTemplate(name);
9943
9497
  Chessboard.getTemplate = (name) => chessboardFactory.getTemplate(name);
9944
9498
  Chessboard.listTemplates = () => chessboardFactory.listTemplates();
9945
9499
 
9946
- // --- STATS & DEBUG ---
9500
+ // Statistics and debugging
9947
9501
  Chessboard.getStats = () => chessboardFactory.getStats();
9948
9502
 
9949
- // --- DEPRECATED/LEGACY ALIASES ---
9950
- /**
9951
- * @deprecated Use Chessboard.create instead
9952
- */
9953
- Chessboard.Class = ChessboardWrapper;
9954
- Chessboard.Chessboard = ChessboardWrapper;
9955
- Chessboard.Config = ChessboardConfig;
9956
- Chessboard.Factory = ChessboardFactory;
9957
-
9958
9503
  /**
9959
9504
  * Coordinate utilities for Chessboard.js
9960
9505
  */