@alepot55/chessboardjs 2.1.5 → 2.1.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.
- package/README.md +312 -2
- package/chessboard.bundle.js +471 -376
- package/chessboard.js +475 -372
- package/chessboard.move.js +0 -1
- package/package.json +1 -1
- package/dist/website/home/bundle.js +0 -3303
package/chessboard.js
CHANGED
|
@@ -47,16 +47,17 @@ class Chessboard {
|
|
|
47
47
|
'invalid_hintColor': 'Invalid hintColor - ',
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
// -------------------
|
|
51
|
+
// Initialization
|
|
52
|
+
// -------------------
|
|
50
53
|
constructor(config) {
|
|
51
54
|
this.config = new ChessboardConfig(config);
|
|
52
55
|
this.init();
|
|
53
56
|
}
|
|
54
57
|
|
|
55
|
-
// Build
|
|
56
|
-
|
|
57
58
|
init() {
|
|
58
59
|
this.initParams();
|
|
59
|
-
this.
|
|
60
|
+
this.setGame(this.config.position);
|
|
60
61
|
this.buildBoard();
|
|
61
62
|
this.buildSquares();
|
|
62
63
|
this.addListeners();
|
|
@@ -68,27 +69,13 @@ class Chessboard {
|
|
|
68
69
|
this.squares = {};
|
|
69
70
|
this.promoting = false;
|
|
70
71
|
this.clicked = null;
|
|
71
|
-
this.movesHistory = [];
|
|
72
72
|
this.mosseIndietro = [];
|
|
73
73
|
this.clicked = null;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
Object.entries(position).forEach(([square, [type, color]]) => {
|
|
80
|
-
this.game.put({ type, color }, square);
|
|
81
|
-
});
|
|
82
|
-
} else if (Object.values(this.standard_positions).includes(position)) {
|
|
83
|
-
if (position === 'start') this.game = new Chess();
|
|
84
|
-
else this.game = new Chess(this.standard_positions[position]);
|
|
85
|
-
} else if (validateFen(position)) {
|
|
86
|
-
this.game = new Chess(position);
|
|
87
|
-
} else {
|
|
88
|
-
throw new Error(this.error_messages['invalid_position'] + position);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
76
|
+
// -------------------
|
|
77
|
+
// Board Setup
|
|
78
|
+
// -------------------
|
|
92
79
|
buildBoard() {
|
|
93
80
|
this.board = document.getElementById(this.config.id_div);
|
|
94
81
|
if (!this.board) {
|
|
@@ -98,12 +85,6 @@ class Chessboard {
|
|
|
98
85
|
this.board.className = "board";
|
|
99
86
|
}
|
|
100
87
|
|
|
101
|
-
realCoord(row, col) {
|
|
102
|
-
if (this.isWhiteOriented()) row = 7 - row;
|
|
103
|
-
else col = 7 - col;
|
|
104
|
-
return [row + 1, col + 1];
|
|
105
|
-
}
|
|
106
|
-
|
|
107
88
|
buildSquares() {
|
|
108
89
|
|
|
109
90
|
for (let row = 0; row < 8; row++) {
|
|
@@ -123,8 +104,80 @@ class Chessboard {
|
|
|
123
104
|
this.board.innerHTML = '';
|
|
124
105
|
}
|
|
125
106
|
|
|
126
|
-
|
|
107
|
+
removeSquares() {
|
|
108
|
+
for (const square of Object.values(this.squares)) {
|
|
109
|
+
this.board.removeChild(square.element);
|
|
110
|
+
square.destroy();
|
|
111
|
+
|
|
112
|
+
}
|
|
113
|
+
this.squares = {};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
resize(value) {
|
|
117
|
+
if (value === 'auto') {
|
|
118
|
+
let size;
|
|
119
|
+
if (this.board.offsetWidth === 0) {
|
|
120
|
+
size = this.board.offsetHeight;
|
|
121
|
+
} else if (this.board.offsetHeight === 0) {
|
|
122
|
+
size = this.board.offsetWidth;
|
|
123
|
+
} else {
|
|
124
|
+
size = Math.min(this.board.offsetWidth, this.board.offsetHeight);
|
|
125
|
+
}
|
|
126
|
+
this.resize(size);
|
|
127
|
+
} else if (typeof value !== 'number') {
|
|
128
|
+
throw new Error(this.error_messages['invalid_value'] + value);
|
|
129
|
+
} else {
|
|
130
|
+
document.documentElement.style.setProperty('--dimBoard', value + 'px');
|
|
131
|
+
this.updateBoardPieces();
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// -------------------
|
|
136
|
+
// Game/Position Functions
|
|
137
|
+
// -------------------
|
|
138
|
+
convertFen(position) {
|
|
139
|
+
if (typeof position === 'string') {
|
|
140
|
+
|
|
141
|
+
if (this.validateFen(position)) return position;
|
|
142
|
+
else if (this.standard_positions[position]) return this.standard_positions[position];
|
|
143
|
+
else throw new Error('Invalid position -' + position);
|
|
144
|
+
} else if (typeof position === 'object') {
|
|
145
|
+
let parts = [];
|
|
146
|
+
for (let row = 0; row < 8; row++) {
|
|
147
|
+
let rowParts = [];
|
|
148
|
+
let empty = 0;
|
|
149
|
+
for (let col = 0; col < 8; col++) {
|
|
150
|
+
let square = this.getSquareID(row, col);
|
|
151
|
+
let piece = position[square];
|
|
152
|
+
if (piece) {
|
|
153
|
+
if (empty > 0) {
|
|
154
|
+
rowParts.push(empty);
|
|
155
|
+
empty = 0;
|
|
156
|
+
}
|
|
157
|
+
// Convert piece notation: white pieces become uppercase, black remain lowercase.
|
|
158
|
+
let fenPiece = piece[1] === 'w' ? piece[0].toUpperCase() : piece[0].toLowerCase();
|
|
159
|
+
rowParts.push(fenPiece);
|
|
160
|
+
} else {
|
|
161
|
+
empty++;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (empty > 0) rowParts.push(empty);
|
|
165
|
+
parts.push(rowParts.join(''));
|
|
166
|
+
}
|
|
167
|
+
return parts.join('/');
|
|
168
|
+
} else {
|
|
169
|
+
throw new Error('Invalid position -' + position);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
setGame(position) {
|
|
174
|
+
const fen = this.convertFen(position);
|
|
175
|
+
this.game = new Chess(fen === 'start' ? this.standard_positions['default'] : null);
|
|
176
|
+
}
|
|
127
177
|
|
|
178
|
+
// -------------------
|
|
179
|
+
// Piece Functions
|
|
180
|
+
// -------------------
|
|
128
181
|
getPiecePath(piece) {
|
|
129
182
|
if (typeof this.config.piecesPath === 'string')
|
|
130
183
|
return this.config.piecesPath + '/' + piece + '.svg';
|
|
@@ -136,41 +189,27 @@ class Chessboard {
|
|
|
136
189
|
throw new Error(this.error_messages['invalid_piecesPath']);
|
|
137
190
|
}
|
|
138
191
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
movePiece(piece, to, duration, callback) {
|
|
145
|
-
piece.translate(to, duration, this.transitionTimingFunction, this.config.moveAnimation, callback);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
translatePiece(move, removeTo, animate, callback = null) {
|
|
149
|
-
|
|
150
|
-
if (removeTo) this.removePieceFromSquare(move.to, false);
|
|
151
|
-
|
|
152
|
-
let change_square = () => {
|
|
153
|
-
move.from.removePiece();
|
|
154
|
-
move.to.putPiece(move.piece);
|
|
155
|
-
move.piece.setDrag(this.dragFunction(move.to, move.piece));
|
|
156
|
-
if (callback) callback();
|
|
192
|
+
convertPiece(piece) {
|
|
193
|
+
if (piece instanceof Piece) return piece;
|
|
194
|
+
if (typeof piece === 'string') {
|
|
195
|
+
let [type, color] = piece.split('');
|
|
196
|
+
return new Piece(color, type, this.getPiecePath(piece));
|
|
157
197
|
}
|
|
198
|
+
throw new Error(this.error_messages['invalid_piece'] + piece);
|
|
199
|
+
}
|
|
158
200
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
this.movePiece(move.piece, move.to, duration, change_square);
|
|
201
|
+
addPieceOnSquare(square, piece, fade = true) {
|
|
162
202
|
|
|
163
|
-
|
|
203
|
+
square.putPiece(piece);
|
|
204
|
+
piece.setDrag(this.dragFunction(square, piece));
|
|
164
205
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
206
|
+
if (fade) piece.fadeIn(
|
|
207
|
+
this.config.fadeTime,
|
|
208
|
+
this.config.fadeAnimation,
|
|
209
|
+
this.transitionTimingFunction
|
|
210
|
+
);
|
|
169
211
|
|
|
170
|
-
|
|
171
|
-
if (square instanceof Square) return square;
|
|
172
|
-
if (typeof square === 'string' && this.squares[square]) return this.squares[square];
|
|
173
|
-
throw new Error('Invalid square value');
|
|
212
|
+
piece.visible();
|
|
174
213
|
}
|
|
175
214
|
|
|
176
215
|
removePieceFromSquare(square, fade = true) {
|
|
@@ -192,110 +231,35 @@ class Chessboard {
|
|
|
192
231
|
return piece;
|
|
193
232
|
}
|
|
194
233
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
event.preventDefault();
|
|
200
|
-
|
|
201
|
-
if (!this.config.draggable || !piece) return;
|
|
202
|
-
if (!this.config.onDragStart(square, piece)) return;
|
|
203
|
-
|
|
204
|
-
let prec;
|
|
205
|
-
let from = square;
|
|
206
|
-
let to = square;
|
|
207
|
-
|
|
208
|
-
const img = piece.element;
|
|
209
|
-
|
|
210
|
-
if (!this.canMove(from)) return;
|
|
211
|
-
if (!this.config.clickable) this.clicked = null;
|
|
212
|
-
if (this.onClick(from)) return;
|
|
213
|
-
|
|
214
|
-
img.style.position = 'absolute';
|
|
215
|
-
img.style.zIndex = 100;
|
|
216
|
-
|
|
217
|
-
const moveAt = (pageX, pageY) => {
|
|
218
|
-
const halfWidth = img.offsetWidth / 2;
|
|
219
|
-
const halfHeight = img.offsetHeight / 2;
|
|
220
|
-
img.style.left = `${pageX - halfWidth}px`;
|
|
221
|
-
img.style.top = `${pageY - halfHeight}px`;
|
|
222
|
-
return true;
|
|
223
|
-
};
|
|
224
|
-
|
|
225
|
-
const onMouseMove = (event) => {
|
|
226
|
-
if (!moveAt(event.pageX, event.pageY)) return;
|
|
227
|
-
|
|
228
|
-
const boardRect = this.board.getBoundingClientRect();
|
|
229
|
-
const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.board;
|
|
230
|
-
const x = event.clientX - boardRect.left;
|
|
231
|
-
const y = event.clientY - boardRect.top;
|
|
232
|
-
|
|
233
|
-
let newTo = null;
|
|
234
|
-
if (x >= 0 && x <= boardWidth && y >= 0 && y <= boardHeight) {
|
|
235
|
-
const col = Math.floor(x / (boardWidth / 8));
|
|
236
|
-
const row = Math.floor(y / (boardHeight / 8));
|
|
237
|
-
newTo = this.squares[this.getSquareID(row, col)];
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
to = newTo;
|
|
241
|
-
this.config.onDragMove(from, to, piece);
|
|
242
|
-
|
|
243
|
-
if (to !== prec) {
|
|
244
|
-
to?.highlight();
|
|
245
|
-
prec?.dehighlight();
|
|
246
|
-
prec = to;
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
const onMouseUp = () => {
|
|
251
|
-
prec?.dehighlight();
|
|
252
|
-
document.removeEventListener('mousemove', onMouseMove);
|
|
253
|
-
window.removeEventListener('mouseup', onMouseUp);
|
|
254
|
-
img.style.zIndex = 20;
|
|
255
|
-
|
|
256
|
-
const dropResult = this.config.onDrop(from, to, piece);
|
|
257
|
-
const isTrashDrop = !to && (this.config.dropOffBoard === 'trash' || dropResult === 'trash');
|
|
234
|
+
movePiece(piece, to, duration, callback) {
|
|
235
|
+
piece.translate(to, duration, this.transitionTimingFunction, this.config.moveAnimation, callback);
|
|
236
|
+
}
|
|
258
237
|
|
|
259
|
-
|
|
260
|
-
this.allSquares("unmoved");
|
|
261
|
-
this.allSquares('removeHint');
|
|
262
|
-
from.deselect();
|
|
263
|
-
this.remove(from);
|
|
264
|
-
} else if (!to || !this.onClick(to, true)) {
|
|
265
|
-
this.snapbackPiece(from, !this.promoting);
|
|
266
|
-
this.config.onSnapbackEnd(from, piece);
|
|
267
|
-
}
|
|
268
|
-
};
|
|
238
|
+
translatePiece(move, removeTo, animate, callback = null) {
|
|
269
239
|
|
|
270
|
-
|
|
271
|
-
document.addEventListener('mousemove', onMouseMove);
|
|
272
|
-
img.addEventListener('mouseup', onMouseUp, { once: true });
|
|
273
|
-
}
|
|
274
|
-
}
|
|
240
|
+
if (removeTo) this.removePieceFromSquare(move.to, false);
|
|
275
241
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
242
|
+
let change_square = () => {
|
|
243
|
+
move.from.removePiece();
|
|
244
|
+
move.to.putPiece(move.piece);
|
|
245
|
+
move.piece.setDrag(this.dragFunction(move.to, move.piece));
|
|
246
|
+
if (callback) callback();
|
|
281
247
|
}
|
|
282
|
-
throw new Error(this.error_messages['invalid_piece'] + piece);
|
|
283
|
-
}
|
|
284
248
|
|
|
285
|
-
|
|
249
|
+
let duration = animate ? this.config.moveTime : 0;
|
|
286
250
|
|
|
287
|
-
|
|
288
|
-
piece.setDrag(this.dragFunction(square, piece));
|
|
251
|
+
this.movePiece(move.piece, move.to, duration, change_square);
|
|
289
252
|
|
|
290
|
-
|
|
291
|
-
this.config.fadeTime,
|
|
292
|
-
this.config.fadeAnimation,
|
|
293
|
-
this.transitionTimingFunction
|
|
294
|
-
);
|
|
253
|
+
}
|
|
295
254
|
|
|
296
|
-
|
|
255
|
+
snapbackPiece(square, animate) {
|
|
256
|
+
let move = new Move(square, square);
|
|
257
|
+
this.translatePiece(move, false, animate);
|
|
297
258
|
}
|
|
298
259
|
|
|
260
|
+
// -------------------
|
|
261
|
+
// Board Update Functions
|
|
262
|
+
// -------------------
|
|
299
263
|
updateBoardPieces(animation = false) {
|
|
300
264
|
let { updatedFlags, escapeFlags, movableFlags, pendingTranslations } = this.prepareBoardUpdateData();
|
|
301
265
|
|
|
@@ -315,9 +279,9 @@ class Chessboard {
|
|
|
315
279
|
for (let squareId in this.squares) {
|
|
316
280
|
let cellPiece = this.squares[squareId].piece;
|
|
317
281
|
let cellPieceId = cellPiece ? cellPiece.getId() : null;
|
|
318
|
-
updatedFlags[squareId] = this.
|
|
282
|
+
updatedFlags[squareId] = this.getGamePieceId(squareId) === cellPieceId;
|
|
319
283
|
escapeFlags[squareId] = false;
|
|
320
|
-
movableFlags[squareId] = cellPiece ? this.
|
|
284
|
+
movableFlags[squareId] = cellPiece ? this.getGamePieceId(squareId) !== cellPieceId : false;
|
|
321
285
|
}
|
|
322
286
|
|
|
323
287
|
return { updatedFlags, escapeFlags, movableFlags, pendingTranslations };
|
|
@@ -325,7 +289,7 @@ class Chessboard {
|
|
|
325
289
|
|
|
326
290
|
identifyPieceTranslations(updatedFlags, escapeFlags, movableFlags, pendingTranslations) {
|
|
327
291
|
Object.values(this.squares).forEach(targetSquare => {
|
|
328
|
-
const newPieceId = this.
|
|
292
|
+
const newPieceId = this.getGamePieceId(targetSquare.id);
|
|
329
293
|
const newPiece = newPieceId && this.convertPiece(newPieceId);
|
|
330
294
|
const currentPiece = targetSquare.piece;
|
|
331
295
|
const currentPieceId = currentPiece ? currentPiece.getId() : null;
|
|
@@ -370,7 +334,7 @@ class Chessboard {
|
|
|
370
334
|
|
|
371
335
|
pendingTranslations.push([currentSource, sourceSquare, targetSquare]);
|
|
372
336
|
|
|
373
|
-
if (!this.
|
|
337
|
+
if (!this.getGamePieceId(sourceSquare.id)) updatedFlags[sourceSquare.id] = true;
|
|
374
338
|
|
|
375
339
|
escapeFlags[sourceSquare.id] = true;
|
|
376
340
|
movableFlags[sourceSquare.id] = false;
|
|
@@ -379,7 +343,6 @@ class Chessboard {
|
|
|
379
343
|
|
|
380
344
|
executePieceTranslations(pendingTranslations, escapeFlags, animation) {
|
|
381
345
|
for (let [_, sourceSquare, targetSquare] of pendingTranslations) {
|
|
382
|
-
console.log('executing translation: ', sourceSquare.id, targetSquare.id);
|
|
383
346
|
let removeTarget = !escapeFlags[targetSquare.id] && targetSquare.piece;
|
|
384
347
|
let moveObj = new Move(sourceSquare, targetSquare);
|
|
385
348
|
this.translatePiece(moveObj, removeTarget, animation);
|
|
@@ -389,7 +352,7 @@ class Chessboard {
|
|
|
389
352
|
// Gestisce gli aggiornamenti residui per ogni cella che non è ancora stata correttamente aggiornata
|
|
390
353
|
processRemainingPieceUpdates(updatedFlags, animation) {
|
|
391
354
|
for (const square of Object.values(this.squares)) {
|
|
392
|
-
let newPieceId = this.
|
|
355
|
+
let newPieceId = this.getGamePieceId(square.id);
|
|
393
356
|
let newPiece = newPieceId ? this.convertPiece(newPieceId) : null;
|
|
394
357
|
let currentPiece = square.piece;
|
|
395
358
|
let currentPieceId = currentPiece ? currentPiece.getId() : null;
|
|
@@ -422,48 +385,128 @@ class Chessboard {
|
|
|
422
385
|
}
|
|
423
386
|
}
|
|
424
387
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
//
|
|
388
|
+
// -------------------
|
|
389
|
+
// Event Handlers and Drag
|
|
390
|
+
// -------------------
|
|
391
|
+
dragFunction(square, piece) {
|
|
428
392
|
|
|
429
|
-
|
|
430
|
-
for (const square of Object.values(this.squares)) {
|
|
393
|
+
return (event) => {
|
|
431
394
|
|
|
432
|
-
|
|
395
|
+
event.preventDefault();
|
|
433
396
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
});
|
|
437
|
-
square.element.addEventListener("mouseout", (e) => {
|
|
438
|
-
if (!this.clicked) this.dehintMoves(square);
|
|
439
|
-
});
|
|
397
|
+
if (!this.config.draggable || !piece) return;
|
|
398
|
+
if (!this.config.onDragStart(square, piece)) return;
|
|
440
399
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
}
|
|
400
|
+
let prec;
|
|
401
|
+
let from = square;
|
|
402
|
+
let to = square;
|
|
445
403
|
|
|
446
|
-
|
|
447
|
-
square.element.addEventListener("touch", handleClick);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
404
|
+
const img = piece.element;
|
|
450
405
|
|
|
451
|
-
|
|
406
|
+
if (!this.canMove(from)) return;
|
|
407
|
+
if (!this.config.clickable) this.clicked = null;
|
|
408
|
+
if (this.onClick(from)) return;
|
|
452
409
|
|
|
453
|
-
|
|
410
|
+
img.style.position = 'absolute';
|
|
411
|
+
img.style.zIndex = 100;
|
|
454
412
|
|
|
455
|
-
|
|
456
|
-
|
|
413
|
+
const moveAt = (pageX, pageY) => {
|
|
414
|
+
const halfWidth = img.offsetWidth / 2;
|
|
415
|
+
const halfHeight = img.offsetHeight / 2;
|
|
416
|
+
img.style.left = `${pageX - halfWidth}px`;
|
|
417
|
+
img.style.top = `${pageY - halfHeight}px`;
|
|
418
|
+
return true;
|
|
419
|
+
};
|
|
457
420
|
|
|
458
|
-
|
|
421
|
+
const onMouseMove = (event) => {
|
|
422
|
+
if (!moveAt(event.pageX, event.pageY)) return;
|
|
459
423
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
424
|
+
const boardRect = this.board.getBoundingClientRect();
|
|
425
|
+
const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.board;
|
|
426
|
+
const x = event.clientX - boardRect.left;
|
|
427
|
+
const y = event.clientY - boardRect.top;
|
|
463
428
|
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
429
|
+
let newTo = null;
|
|
430
|
+
if (x >= 0 && x <= boardWidth && y >= 0 && y <= boardHeight) {
|
|
431
|
+
const col = Math.floor(x / (boardWidth / 8));
|
|
432
|
+
const row = Math.floor(y / (boardHeight / 8));
|
|
433
|
+
newTo = this.squares[this.getSquareID(row, col)];
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
to = newTo;
|
|
437
|
+
this.config.onDragMove(from, to, piece);
|
|
438
|
+
|
|
439
|
+
if (to !== prec) {
|
|
440
|
+
to?.highlight();
|
|
441
|
+
prec?.dehighlight();
|
|
442
|
+
prec = to;
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
const onMouseUp = () => {
|
|
447
|
+
prec?.dehighlight();
|
|
448
|
+
document.removeEventListener('mousemove', onMouseMove);
|
|
449
|
+
window.removeEventListener('mouseup', onMouseUp);
|
|
450
|
+
img.style.zIndex = 20;
|
|
451
|
+
|
|
452
|
+
const dropResult = this.config.onDrop(from, to, piece);
|
|
453
|
+
const isTrashDrop = !to && (this.config.dropOffBoard === 'trash' || dropResult === 'trash');
|
|
454
|
+
|
|
455
|
+
if (isTrashDrop) {
|
|
456
|
+
this.allSquares("unmoved");
|
|
457
|
+
this.allSquares('removeHint');
|
|
458
|
+
from.deselect();
|
|
459
|
+
this.remove(from);
|
|
460
|
+
} else if (!to || !this.onClick(to, true)) {
|
|
461
|
+
this.snapbackPiece(from, !this.promoting);
|
|
462
|
+
this.config.onSnapbackEnd(from, piece);
|
|
463
|
+
}
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
window.addEventListener('mouseup', onMouseUp, { once: true });
|
|
467
|
+
document.addEventListener('mousemove', onMouseMove);
|
|
468
|
+
img.addEventListener('mouseup', onMouseUp, { once: true });
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
addListeners() {
|
|
473
|
+
for (const square of Object.values(this.squares)) {
|
|
474
|
+
|
|
475
|
+
let piece = square.piece;
|
|
476
|
+
|
|
477
|
+
square.element.addEventListener("mouseover", (e) => {
|
|
478
|
+
if (!this.clicked) this.hintMoves(square);
|
|
479
|
+
});
|
|
480
|
+
square.element.addEventListener("mouseout", (e) => {
|
|
481
|
+
if (!this.clicked) this.dehintMoves(square);
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
const handleClick = (e) => {
|
|
485
|
+
e.stopPropagation();
|
|
486
|
+
if (this.config.clickable && (!piece || this.config.onlyLegalMoves)) this.onClick(square)
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
square.element.addEventListener("click", handleClick);
|
|
490
|
+
square.element.addEventListener("touch", handleClick);
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
onClick(square, animation = this.config.moveAnimation) {
|
|
495
|
+
|
|
496
|
+
if (square.id === this.clicked?.id) return false;
|
|
497
|
+
|
|
498
|
+
let from = this.clicked;
|
|
499
|
+
this.clicked = null;
|
|
500
|
+
|
|
501
|
+
let promotion = null
|
|
502
|
+
|
|
503
|
+
if (this.promoting) {
|
|
504
|
+
if (this.promoting === 'none') from = null
|
|
505
|
+
else promotion = this.promoting;
|
|
506
|
+
|
|
507
|
+
this.promoting = false;
|
|
508
|
+
this.allSquares("removePromotion");
|
|
509
|
+
this.allSquares("removeCover");
|
|
467
510
|
}
|
|
468
511
|
|
|
469
512
|
if (!from) {
|
|
@@ -496,31 +539,9 @@ class Chessboard {
|
|
|
496
539
|
return false;
|
|
497
540
|
}
|
|
498
541
|
|
|
499
|
-
//
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
if (!this.config.hints || !this.squares[square]) return;
|
|
503
|
-
this.squares[square].putHint(this.colorPiece(square) && this.colorPiece(square) !== this.turn());
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
hintMoves(square) {
|
|
507
|
-
if (!this.canMove(square)) return;
|
|
508
|
-
let mosse = this.game.moves({ square: square.id, verbose: true });
|
|
509
|
-
for (let mossa of mosse) {
|
|
510
|
-
if (mossa['to'].length === 2) this.hint(mossa['to']);
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
dehintMoves(square) {
|
|
515
|
-
let mosse = this.game.moves({ square: square.id, verbose: true });
|
|
516
|
-
for (let mossa of mosse) {
|
|
517
|
-
let to = this.squares[mossa['to']];
|
|
518
|
-
to.removeHint();
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// Moves
|
|
523
|
-
|
|
542
|
+
// -------------------
|
|
543
|
+
// Move Functions
|
|
544
|
+
// -------------------
|
|
524
545
|
canMove(square) {
|
|
525
546
|
if (!square.piece) return false;
|
|
526
547
|
if (this.config.movableColors === 'none') return false;
|
|
@@ -541,13 +562,6 @@ class Chessboard {
|
|
|
541
562
|
throw new Error("Invalid move format");
|
|
542
563
|
}
|
|
543
564
|
|
|
544
|
-
allSquares(method) {
|
|
545
|
-
for (const square of Object.values(this.squares)) {
|
|
546
|
-
square[method]();
|
|
547
|
-
this.squares[square.id] = square;
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
|
|
551
565
|
legalMove(move) {
|
|
552
566
|
let legal_moves = this.legalMoves(move.from.id);
|
|
553
567
|
|
|
@@ -565,50 +579,72 @@ class Chessboard {
|
|
|
565
579
|
return this.game.moves({ verbose: verb });
|
|
566
580
|
}
|
|
567
581
|
|
|
568
|
-
|
|
582
|
+
move(move, animation) {
|
|
583
|
+
move = this.convertMove(move);
|
|
584
|
+
move.check();
|
|
569
585
|
|
|
570
|
-
|
|
571
|
-
let
|
|
572
|
-
parts[1] = color;
|
|
573
|
-
return parts.join(' ');
|
|
574
|
-
}
|
|
586
|
+
let from = move.from;
|
|
587
|
+
let to = move.to;
|
|
575
588
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
589
|
+
if (!this.config.onlyLegalMoves) {
|
|
590
|
+
let piece = this.getGamePieceId(from.id);
|
|
591
|
+
this.game.remove(from.id);
|
|
592
|
+
this.game.remove(to.id);
|
|
593
|
+
this.game.put({ type: move.hasPromotion() ? move.promotion : piece[0], color: piece[1] }, to.id);
|
|
594
|
+
this.updateBoardPieces(animation);
|
|
595
|
+
} else {
|
|
596
|
+
this.allSquares("unmoved");
|
|
581
597
|
|
|
582
|
-
|
|
583
|
-
|
|
598
|
+
move = this.game.move({
|
|
599
|
+
from: from.id,
|
|
600
|
+
to: to.id,
|
|
601
|
+
promotion: move.hasPromotion() ? move.promotion : undefined
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
if (move === null) {
|
|
605
|
+
throw new Error("Invalid move: move could not be executed");
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
this.updateBoardPieces(animation);
|
|
609
|
+
|
|
610
|
+
from.moved();
|
|
611
|
+
to.moved();
|
|
612
|
+
this.allSquares("removeHint");
|
|
613
|
+
|
|
614
|
+
this.config.onMoveEnd(move);
|
|
615
|
+
}
|
|
584
616
|
}
|
|
585
617
|
|
|
586
|
-
|
|
618
|
+
// -------------------
|
|
619
|
+
// Miscellaneous Functions
|
|
620
|
+
// -------------------
|
|
621
|
+
hint(squareId) {
|
|
622
|
+
let square = this.squares[squareId];
|
|
623
|
+
if (!this.config.hints || !square) return;
|
|
624
|
+
square.putHint(square.piece && square.piece.color !== this.turn());
|
|
625
|
+
}
|
|
587
626
|
|
|
588
|
-
|
|
627
|
+
hintMoves(square) {
|
|
628
|
+
if (!this.canMove(square)) return;
|
|
629
|
+
let mosse = this.game.moves({ square: square.id, verbose: true });
|
|
630
|
+
for (let mossa of mosse) {
|
|
631
|
+
if (mossa['to'].length === 2) this.hint(mossa['to']);
|
|
632
|
+
}
|
|
633
|
+
}
|
|
589
634
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
col = col + 1;
|
|
596
|
-
} else {
|
|
597
|
-
row = row + 1;
|
|
598
|
-
col = 8 - col;
|
|
635
|
+
dehintMoves(square) {
|
|
636
|
+
let mosse = this.game.moves({ square: square.id, verbose: true });
|
|
637
|
+
for (let mossa of mosse) {
|
|
638
|
+
let to = this.squares[mossa['to']];
|
|
639
|
+
to.removeHint();
|
|
599
640
|
}
|
|
600
|
-
let letters = 'abcdefgh';
|
|
601
|
-
let letter = letters[col - 1];
|
|
602
|
-
return letter + row;
|
|
603
641
|
}
|
|
604
642
|
|
|
605
|
-
|
|
643
|
+
allSquares(method) {
|
|
606
644
|
for (const square of Object.values(this.squares)) {
|
|
607
|
-
|
|
608
|
-
square.
|
|
609
|
-
|
|
645
|
+
square[method]();
|
|
646
|
+
this.squares[square.id] = square;
|
|
610
647
|
}
|
|
611
|
-
this.squares = {};
|
|
612
648
|
}
|
|
613
649
|
|
|
614
650
|
promote(move) {
|
|
@@ -666,57 +702,72 @@ class Chessboard {
|
|
|
666
702
|
}
|
|
667
703
|
}
|
|
668
704
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
705
|
+
clearSquares() {
|
|
706
|
+
this.allSquares('removeHint');
|
|
707
|
+
this.allSquares("deselect");
|
|
708
|
+
this.allSquares("unmoved");
|
|
673
709
|
}
|
|
674
710
|
|
|
675
|
-
|
|
676
|
-
|
|
711
|
+
getGamePieceId(squareId) {
|
|
712
|
+
let piece = this.game.get(squareId);
|
|
713
|
+
return piece ? piece['type'] + piece['color'] : null;
|
|
677
714
|
}
|
|
678
715
|
|
|
679
|
-
|
|
680
|
-
return this.game.fen();
|
|
681
|
-
}
|
|
716
|
+
isPiece(piece, square) { return this.getGamePieceId(square) === piece }
|
|
682
717
|
|
|
683
|
-
|
|
684
|
-
|
|
718
|
+
realCoord(row, col) {
|
|
719
|
+
if (this.isWhiteOriented()) row = 7 - row;
|
|
720
|
+
else col = 7 - col;
|
|
721
|
+
return [row + 1, col + 1];
|
|
685
722
|
}
|
|
686
723
|
|
|
687
|
-
|
|
688
|
-
|
|
724
|
+
getSquareID(row, col) {
|
|
725
|
+
row = parseInt(row);
|
|
726
|
+
col = parseInt(col);
|
|
727
|
+
if (this.isWhiteOriented()) {
|
|
728
|
+
row = 8 - row;
|
|
729
|
+
col = col + 1;
|
|
730
|
+
} else {
|
|
731
|
+
row = row + 1;
|
|
732
|
+
col = 8 - col;
|
|
733
|
+
}
|
|
734
|
+
let letters = 'abcdefgh';
|
|
735
|
+
let letter = letters[col - 1];
|
|
736
|
+
return letter + row;
|
|
689
737
|
}
|
|
690
738
|
|
|
691
|
-
|
|
692
|
-
return
|
|
739
|
+
convertSquare(square) {
|
|
740
|
+
if (square instanceof Square) return square;
|
|
741
|
+
if (typeof square === 'string' && this.squares[square]) return this.squares[square];
|
|
742
|
+
throw new Error(this.error_messages['invalid_square'] + square);
|
|
693
743
|
}
|
|
694
744
|
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
return
|
|
745
|
+
// -------------------
|
|
746
|
+
// User API and Chess.js Integration
|
|
747
|
+
// -------------------
|
|
748
|
+
getOrientation() {
|
|
749
|
+
return this.config.orientation;
|
|
700
750
|
}
|
|
701
751
|
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
this.allSquares("deselect");
|
|
705
|
-
this.allSquares("unmoved");
|
|
706
|
-
if (color && color !== this.config.orientation) {
|
|
707
|
-
position = this.changeFenColor(position);
|
|
752
|
+
setOrientation(color, animation = true) {
|
|
753
|
+
if (!['w', 'b'].includes(color)) {
|
|
708
754
|
this.config.orientation = color;
|
|
709
|
-
this.
|
|
710
|
-
this.init();
|
|
755
|
+
this.flip(animation);
|
|
711
756
|
} else {
|
|
712
|
-
|
|
713
|
-
this.updateBoardPieces();
|
|
757
|
+
throw new Error(this.error_messages['invalid_orientation'] + color);
|
|
714
758
|
}
|
|
715
759
|
}
|
|
716
760
|
|
|
761
|
+
lastMove() {
|
|
762
|
+
const moves = this.history({ verbose: true });
|
|
763
|
+
return moves[moves.length - 1];
|
|
764
|
+
}
|
|
765
|
+
|
|
717
766
|
flip() {
|
|
718
|
-
|
|
719
|
-
this.
|
|
767
|
+
this.config.orientation = this.config.orientation === 'w' ? 'b' : 'w';
|
|
768
|
+
this.destroy();
|
|
769
|
+
this.initParams();
|
|
770
|
+
this.build();
|
|
720
771
|
}
|
|
721
772
|
|
|
722
773
|
build() {
|
|
@@ -724,127 +775,179 @@ class Chessboard {
|
|
|
724
775
|
this.init();
|
|
725
776
|
}
|
|
726
777
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
778
|
+
destroy() {
|
|
779
|
+
this.removeSquares();
|
|
780
|
+
this.removeBoard();
|
|
781
|
+
}
|
|
730
782
|
|
|
731
|
-
|
|
732
|
-
|
|
783
|
+
ascii() {
|
|
784
|
+
return this.game.ascii();
|
|
785
|
+
}
|
|
733
786
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
this.game.remove(to.id);
|
|
738
|
-
this.game.put({ type: move.hasPromotion() ? move.promotion : piece[0], color: piece[1] }, to.id);
|
|
739
|
-
this.updateBoardPieces(animation);
|
|
740
|
-
} else {
|
|
741
|
-
this.allSquares("unmoved");
|
|
787
|
+
board() {
|
|
788
|
+
return this.game.board();
|
|
789
|
+
}
|
|
742
790
|
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
});
|
|
791
|
+
clear(options = {}, animation = true) {
|
|
792
|
+
this.game.clear(options);
|
|
793
|
+
this.updateBoardPieces(animation);
|
|
794
|
+
}
|
|
748
795
|
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
796
|
+
fen() {
|
|
797
|
+
return this.game.fen();
|
|
798
|
+
}
|
|
752
799
|
|
|
753
|
-
|
|
800
|
+
get(squareId) {
|
|
801
|
+
const square = this.convertSquare(squareId);
|
|
802
|
+
square.check();
|
|
803
|
+
return square.piece;
|
|
804
|
+
}
|
|
754
805
|
|
|
755
|
-
|
|
806
|
+
getCastlingRights(color) {
|
|
807
|
+
return this.game.getCastlingRights(color);
|
|
808
|
+
}
|
|
756
809
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
810
|
+
getComment() {
|
|
811
|
+
return this.game.getComment();
|
|
812
|
+
}
|
|
760
813
|
|
|
761
|
-
|
|
762
|
-
|
|
814
|
+
getComments() {
|
|
815
|
+
return this.game.getComments();
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
history(options = {}) {
|
|
819
|
+
return this.game.history(options);
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
isCheckmate() {
|
|
823
|
+
return this.game.isCheckmate();
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
isDraw() {
|
|
827
|
+
return this.game.isDraw();
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
isDrawByFiftyMoves() {
|
|
831
|
+
return this.game.isDrawByFiftyMoves();
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
isInsufficientMaterial() {
|
|
835
|
+
return this.game.isInsufficientMaterial();
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
isGameOver() {
|
|
839
|
+
return this.game.isGameOver();
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
isStalemate() {
|
|
843
|
+
return this.game.isStalemate();
|
|
763
844
|
}
|
|
764
845
|
|
|
765
|
-
|
|
766
|
-
this.game.
|
|
846
|
+
isThreefoldRepetition() {
|
|
847
|
+
return this.game.isThreefoldRepetition();
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
load(fen, options = {}, animation = true) {
|
|
851
|
+
this.clearSquares();
|
|
852
|
+
this.game.load(fen, options);
|
|
767
853
|
this.updateBoardPieces(animation);
|
|
768
854
|
}
|
|
769
855
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
square.check();
|
|
774
|
-
piece.check();
|
|
775
|
-
if (square.piece) this.remove(square);
|
|
776
|
-
this.game.put({ type: piece.type, color: piece.color }, square.id);
|
|
856
|
+
loadPgn(pgn, options = {}, animation = true) {
|
|
857
|
+
this.clearSquares();
|
|
858
|
+
this.game.loadPgn(pgn, options);
|
|
777
859
|
this.updateBoardPieces();
|
|
778
860
|
}
|
|
779
861
|
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
if (this.game.inCheck()) return this.game.turn() === 'w' ? 'b' : 'w';
|
|
783
|
-
return 'd';
|
|
784
|
-
}
|
|
785
|
-
return null;
|
|
862
|
+
moveNumber() {
|
|
863
|
+
return this.game.moveNumber();
|
|
786
864
|
}
|
|
787
865
|
|
|
788
|
-
|
|
789
|
-
|
|
866
|
+
moves(options = {}) {
|
|
867
|
+
return this.game.moves(options);
|
|
790
868
|
}
|
|
791
869
|
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
let size;
|
|
795
|
-
if (this.board.offsetWidth === 0) {
|
|
796
|
-
size = this.board.offsetHeight;
|
|
797
|
-
} else if (this.board.offsetHeight === 0) {
|
|
798
|
-
size = this.board.offsetWidth;
|
|
799
|
-
} else {
|
|
800
|
-
size = Math.min(this.board.offsetWidth, this.board.offsetHeight);
|
|
801
|
-
}
|
|
802
|
-
this.resize(size);
|
|
803
|
-
} else if (typeof value !== 'number') {
|
|
804
|
-
throw new Error(this.error_messages['invalid_value'] + value);
|
|
805
|
-
} else {
|
|
806
|
-
document.documentElement.style.setProperty('--dimBoard', value + 'px');
|
|
807
|
-
this.updateBoardPieces();
|
|
808
|
-
}
|
|
870
|
+
pgn(options = {}) {
|
|
871
|
+
return this.game.pgn(options);
|
|
809
872
|
}
|
|
810
873
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
this.
|
|
814
|
-
this.
|
|
815
|
-
|
|
816
|
-
this.movesHistory = [];
|
|
817
|
-
this.mosseIndietro = [];
|
|
818
|
-
this.clicked = null;
|
|
819
|
-
this.board = null;
|
|
874
|
+
put(pieceId, squareId, animation = true) {
|
|
875
|
+
const [type, color] = pieceId.split('');
|
|
876
|
+
const success = this.game.put({ type: type, color: color }, squareId);
|
|
877
|
+
if (success) this.updateBoardPieces(animation);
|
|
878
|
+
return success;
|
|
820
879
|
}
|
|
821
880
|
|
|
822
|
-
remove(
|
|
823
|
-
|
|
824
|
-
square.check();
|
|
825
|
-
this.game.remove(square.id);
|
|
826
|
-
let piece = square.piece;
|
|
881
|
+
remove(squareId, animation = true) {
|
|
882
|
+
const removedPiece = this.game.remove(squareId);
|
|
827
883
|
this.updateBoardPieces(animation);
|
|
828
|
-
return
|
|
884
|
+
return removedPiece;
|
|
829
885
|
}
|
|
830
886
|
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
return piece ? piece['type'] + piece['color'] : null;
|
|
887
|
+
removeComment() {
|
|
888
|
+
return this.game.removeComment();
|
|
834
889
|
}
|
|
835
890
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
square.check();
|
|
839
|
-
square.highlight();
|
|
891
|
+
removeComments() {
|
|
892
|
+
return this.game.removeComments();
|
|
840
893
|
}
|
|
841
894
|
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
895
|
+
removeHeader(field) {
|
|
896
|
+
return this.game.removeHeader(field);
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
reset(animation = true) {
|
|
900
|
+
this.game.reset();
|
|
901
|
+
this.updateBoardPieces(animation);
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
setCastlingRights(color, rights) {
|
|
905
|
+
return this.game.setCastlingRights(color, rights);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
setComment(comment) {
|
|
909
|
+
this.game.setComment(comment);
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
setHeader(key, value) {
|
|
913
|
+
return this.game.setHeader(key, value);
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
squareColor(squareId) {
|
|
917
|
+
return this.game.squareColor(squareId);
|
|
846
918
|
}
|
|
847
919
|
|
|
920
|
+
turn() {
|
|
921
|
+
return this.game.turn();
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
undo() {
|
|
925
|
+
const move = this.game.undo();
|
|
926
|
+
if (move) this.updateBoardPieces();
|
|
927
|
+
return move;
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
validateFen(fen) {
|
|
931
|
+
return validateFen(fen);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// -------------------
|
|
935
|
+
// Other Utility Functions
|
|
936
|
+
// -------------------
|
|
937
|
+
chageFenTurn(fen, color) {
|
|
938
|
+
let parts = fen.split(' ');
|
|
939
|
+
parts[1] = color;
|
|
940
|
+
return parts.join(' ');
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
changeFenColor(fen) {
|
|
944
|
+
let parts = fen.split(' ');
|
|
945
|
+
parts[1] = parts[1] === 'w' ? 'b' : 'w';
|
|
946
|
+
return parts.join(' ');
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
isWhiteOriented() { return this.config.orientation === 'w' }
|
|
950
|
+
|
|
848
951
|
}
|
|
849
952
|
|
|
850
953
|
export default Chessboard;
|