@alepot55/chessboardjs 1.1.0 → 2.0.3

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.
@@ -0,0 +1,56 @@
1
+ import Piece from "./chessboard.piece.js";
2
+ import Square from "./chessboard.square.js";
3
+
4
+ class Move {
5
+
6
+ constructor(from, to, promotion = null, check = false) {
7
+ this.piece = from.getPiece();
8
+ this.from = from;
9
+ this.to = to;
10
+ this.promotion = promotion;
11
+
12
+ if (check) this.check();
13
+ }
14
+
15
+ hasPromotion() {
16
+ return this.promotion !== null;
17
+ }
18
+
19
+ setPromotion(promotion) {
20
+ this.promotion = promotion;
21
+ }
22
+
23
+ check() {
24
+ if (this.piece === null) {
25
+ console.log(this);
26
+ throw new Error("Invalid move: piece is null");
27
+ }
28
+ if (!(this.piece instanceof Piece)) {
29
+ throw new Error("Invalid move: piece is not an instance of Piece");
30
+ }
31
+ if (['q', 'r', 'b', 'n', null].indexOf(this.promotion) === -1) {
32
+ throw new Error("Invalid move: promotion is not valid");
33
+ }
34
+ if (!(this.from instanceof Square)) {
35
+ throw new Error("Invalid move: from is not an instance of Square");
36
+ }
37
+ if (!(this.to instanceof Square)) {
38
+ throw new Error("Invalid move: to is not an instance of Square");
39
+ }
40
+ if (!this.to) {
41
+ throw new Error("Invalid move: to is null or undefined");
42
+ }
43
+ if (!this.from) {
44
+ throw new Error("Invalid move: from is null or undefined");
45
+ }
46
+ }
47
+
48
+ isLegal(game) {
49
+ let destinations = game.moves({ square: this.from.id, verbose: true }).map(move => move.to);
50
+ return destinations.indexOf(this.to.id) !== -1;
51
+ }
52
+
53
+
54
+ }
55
+
56
+ export default Move;
@@ -0,0 +1,115 @@
1
+ class Piece {
2
+ constructor(color, type, src, opacity = 1) {
3
+ this.color = color;
4
+ this.type = type;
5
+ this.id = this.getId();
6
+ this.src = src;
7
+ this.element = this.createElement(src, opacity);
8
+
9
+ this.check();
10
+ }
11
+
12
+ getId() { return this.type + this.color }
13
+
14
+ createElement(opacity) {
15
+ let element = document.createElement("img");
16
+ element.classList.add("piece");
17
+ element.id = this.id;
18
+ element.src = this.src;
19
+ element.style.opacity = opacity;
20
+ return element;
21
+ }
22
+
23
+ visible() { this.element.style.opacity = 1 }
24
+
25
+ invisible() { this.element.style.opacity = 0 }
26
+
27
+ fadeIn(duration, speed, transition_f) {
28
+ let start = performance.now();
29
+ let opacity = 0;
30
+ let piece = this;
31
+ let fade = function () {
32
+ let elapsed = performance.now() - start;
33
+ opacity = transition_f(elapsed, duration, speed);
34
+ piece.element.style.opacity = opacity;
35
+ if (elapsed < duration) {
36
+ requestAnimationFrame(fade);
37
+ } else {
38
+ piece.element.style.opacity = 1;
39
+ }
40
+ }
41
+ fade();
42
+ }
43
+
44
+ fadeOut(duration, speed, transition_f) {
45
+ let start = performance.now();
46
+ let opacity = 1;
47
+ let piece = this;
48
+ let fade = function () {
49
+ let elapsed = performance.now() - start;
50
+ opacity = 1 - transition_f(elapsed, duration, speed);
51
+ piece.element.style.opacity = opacity;
52
+ if (elapsed < duration) {
53
+ requestAnimationFrame(fade);
54
+ } else {
55
+ piece.element.style.opacity = 0;
56
+ }
57
+ }
58
+ }
59
+
60
+ setDrag(f) {
61
+ this.element.ondragstart = () => false;
62
+ this.element.onmousedown = f;
63
+ }
64
+
65
+ destroy() {
66
+ this.element.remove();
67
+ }
68
+
69
+ translate(to, duration, transition_f, speed, callback = null) {
70
+
71
+ let sourceRect = this.element.getBoundingClientRect();
72
+ let targetRect = to.getBoundingClientRect();
73
+ let x_start = sourceRect.left + sourceRect.width / 2;
74
+ let y_start = sourceRect.top + sourceRect.height / 2;
75
+ let x_end = targetRect.left + targetRect.width / 2;
76
+ let y_end = targetRect.top + targetRect.height / 2;
77
+ let dx = x_end - x_start;
78
+ let dy = y_end - y_start;
79
+
80
+ let keyframes = [
81
+ { transform: 'translate(0, 0)' },
82
+ { transform: `translate(${dx}px, ${dy}px)` }
83
+ ];
84
+
85
+ if (this.element.animate) {
86
+ let animation = this.element.animate(keyframes, {
87
+ duration: duration,
88
+ easing: 'ease',
89
+ fill: 'none'
90
+ });
91
+
92
+ animation.onfinish = () => {
93
+ if (callback) callback();
94
+ this.element.style = '';
95
+ };
96
+ } else {
97
+ this.element.style.transition = `transform ${duration}ms ease`;
98
+ this.element.style.transform = `translate(${dx}px, ${dy}px)`;
99
+ if (callback) callback();
100
+ this.element.style = '';
101
+ }
102
+ }
103
+
104
+ check() {
105
+ if (['p', 'r', 'n', 'b', 'q', 'k'].indexOf(this.type) === -1) {
106
+ throw new Error("Invalid piece type");
107
+ }
108
+
109
+ if (['w', 'b'].indexOf(this.color) === -1) {
110
+ throw new Error("Invalid piece color");
111
+ }
112
+ }
113
+ }
114
+
115
+ export default Piece;
@@ -0,0 +1,184 @@
1
+ import Piece from "./chessboard.piece.js";
2
+
3
+ class Square {
4
+
5
+ constructor(row, col) {
6
+ this.row = row;
7
+ this.col = col;
8
+ this.id = this.getId();
9
+ this.element = this.createElement();
10
+ this.piece = null;
11
+ }
12
+
13
+ getPiece() {
14
+ return this.piece;
15
+ }
16
+
17
+ opposite() {
18
+ this.row = 9 - this.row;
19
+ this.col = 9 - this.col;
20
+ this.id = this.getId();
21
+ this.element = this.resetElement();
22
+ }
23
+
24
+ isWhite() {
25
+ return (this.row + this.col) % 2 === 0;
26
+ }
27
+
28
+ getId() {
29
+ let letters = 'abcdefgh';
30
+ let letter = letters[this.col - 1];
31
+ return letter + this.row;
32
+ }
33
+
34
+ resetElement() {
35
+ this.element.id = this.id;
36
+ this.element.className = '';
37
+ this.element.classList.add('square');
38
+ this.element.classList.add(this.isWhite() ? 'whiteSquare' : 'blackSquare');
39
+ }
40
+
41
+ createElement() {
42
+ let element = document.createElement('div');
43
+ element.id = this.id;
44
+ element.classList.add('square');
45
+ element.classList.add(this.isWhite() ? 'whiteSquare' : 'blackSquare');
46
+ return element;
47
+ }
48
+
49
+ getElement() {
50
+ return this.element;
51
+ }
52
+
53
+ getBoundingClientRect() {
54
+ return this.element.getBoundingClientRect();
55
+ }
56
+
57
+ removePiece() {
58
+ this.element.removeChild(this.piece.element);
59
+ const piece = this.piece;
60
+ this.piece = null;
61
+ return piece;
62
+ }
63
+
64
+ addEventListener(event, callback) {
65
+ this.element.addEventListener(event, callback);
66
+ }
67
+
68
+ putPiece(piece) {
69
+ this.piece = piece;
70
+ this.element.appendChild(piece.element);
71
+ }
72
+
73
+ putHint(catchable) {
74
+ if (this.element.querySelector('.hint')) {
75
+ return;
76
+ }
77
+ let hint = document.createElement("div");
78
+ hint.classList.add('hint');
79
+ this.element.appendChild(hint);
80
+ if (catchable) {
81
+ hint.classList.add('catchable');
82
+ }
83
+ }
84
+
85
+ removeHint() {
86
+ let hint = this.element.querySelector('.hint');
87
+ if (hint) {
88
+ this.element.removeChild(hint);
89
+ }
90
+ }
91
+
92
+ select() {
93
+ this.element.classList.add(this.isWhite() ? 'selectedSquareWhite' : 'selectedSquareBlack');
94
+ }
95
+
96
+ deselect() {
97
+ this.element.classList.remove('selectedSquareWhite');
98
+ this.element.classList.remove('selectedSquareBlack');
99
+ }
100
+
101
+ moved() {
102
+ this.element.classList.add(this.isWhite() ? 'movedSquareWhite' : 'movedSquareBlack');
103
+ }
104
+
105
+ unmoved() {
106
+ this.element.classList.remove('movedSquareWhite');
107
+ this.element.classList.remove('movedSquareBlack');
108
+ }
109
+
110
+ highlight() {
111
+ this.element.classList.add('highlighted');
112
+ }
113
+
114
+ dehighlight() {
115
+ this.element.classList.remove('highlighted');
116
+ }
117
+
118
+ putCover(callback) {
119
+ let cover = document.createElement("div");
120
+ cover.classList.add('square');
121
+ cover.classList.add('cover');
122
+ this.element.appendChild(cover);
123
+ cover.addEventListener('click', (e) => {
124
+ e.stopPropagation();
125
+ callback();
126
+ });
127
+ }
128
+
129
+ removeCover() {
130
+ let cover = this.element.querySelector('.cover');
131
+ if (cover) {
132
+ this.element.removeChild(cover);
133
+ }
134
+ }
135
+
136
+ putPromotion(src, callback) {
137
+ let choice = document.createElement("div");
138
+ choice.classList.add('square');
139
+ choice.classList.add('choice');
140
+ this.element.appendChild(choice);
141
+ let img = document.createElement("img");
142
+ img.classList.add("piece");
143
+ img.classList.add("choicable");
144
+ img.src = src;
145
+ choice.appendChild(img);
146
+ choice.addEventListener('click', (e) => {
147
+ e.stopPropagation();
148
+ callback();
149
+ });
150
+
151
+ }
152
+
153
+ removePromotion() {
154
+ let choice = this.element.querySelector('.choice');
155
+ if (choice) {
156
+ choice.removeChild(choice.firstChild);
157
+ this.element.removeChild(choice);
158
+ }
159
+ }
160
+
161
+ destroy() {
162
+ this.element.remove();
163
+ }
164
+
165
+ hasPiece() {
166
+ return this.piece !== null;
167
+ }
168
+
169
+ getColor() {
170
+ return this.piece.getColor();
171
+ }
172
+
173
+ check() {
174
+ if (this.row < 1 || this.row > 8) {
175
+ throw new Error("Invalid square: row is out of bounds");
176
+ }
177
+ if (this.col < 1 || this.col > 8) {
178
+ throw new Error("Invalid square: col is out of bounds");
179
+ }
180
+
181
+ }
182
+ }
183
+
184
+ export default Square;
package/jest.config.js ADDED
@@ -0,0 +1,7 @@
1
+ export default {
2
+ testEnvironment: 'jsdom',
3
+ transform: {
4
+ "^.+\\.js$": "babel-jest"
5
+ }
6
+ // ...existing config...
7
+ };
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "dependencies": {
3
- "chess.js": "^1.0.0-beta.8"
3
+ "chess.js": "^1.0.0"
4
4
  },
5
5
  "name": "@alepot55/chessboardjs",
6
- "version": "1.1.0",
6
+ "version": "2.0.3",
7
7
  "main": "chessboard.js",
8
8
  "type": "module",
9
9
  "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1"
10
+ "test": "jest"
11
11
  },
12
12
  "author": "alepot55",
13
13
  "license": "ISC",
@@ -23,5 +23,12 @@
23
23
  "bugs": {
24
24
  "url": "https://github.com/alepot55/ChessBoard/issues"
25
25
  },
26
- "homepage": "https://github.com/alepot55/ChessBoard#readme"
26
+ "homepage": "https://github.com/alepot55/ChessBoard#readme",
27
+ "devDependencies": {
28
+ "@babel/core": "^7.26.8",
29
+ "@babel/preset-env": "^7.26.8",
30
+ "babel-jest": "^29.7.0",
31
+ "jest": "^29.7.0",
32
+ "jest-environment-jsdom": "^29.7.0"
33
+ }
27
34
  }
@@ -0,0 +1,128 @@
1
+ import Chessboard from '../chessboard.js';
2
+
3
+ describe('Chessboard User Functions', () => {
4
+ let chessboard;
5
+ let config = { id_div: 'board', size: 400, position: 'start', orientation: 'w' };
6
+
7
+ beforeEach(() => {
8
+ document.body.innerHTML = '<div id="board"></div>';
9
+ chessboard = new Chessboard(config);
10
+ });
11
+
12
+ test('turn() should return the current turn', () => {
13
+ expect(chessboard.turn()).toBe('w');
14
+ });
15
+
16
+ test('getOrientation() should return the current orientation', () => {
17
+ expect(chessboard.getOrientation()).toBe('w');
18
+ });
19
+
20
+ test('fen() should return the current FEN string', () => {
21
+ expect(chessboard.fen()).toBe('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
22
+ });
23
+
24
+ test('lastMove() should return the last move made', () => {
25
+ chessboard.move('e2e4');
26
+ expect(chessboard.lastMove().san).toBe('e4');
27
+ });
28
+
29
+ test('history() should return the history of moves', () => {
30
+ chessboard.move('e2e4');
31
+ chessboard.move('e7e5');
32
+ expect(chessboard.history().length).toBe(2);
33
+ });
34
+
35
+ test('get() should return the piece on the given square', () => {
36
+ expect(chessboard.get('e2')).toBe('pw');
37
+ });
38
+
39
+ test('position() should set the board to the given position', () => {
40
+ chessboard.position('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
41
+ expect(chessboard.fen()).toBe('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
42
+ });
43
+
44
+ test('flip() should flip the board orientation', () => {
45
+ chessboard.flip();
46
+ expect(chessboard.getOrientation()).toBe('b');
47
+ });
48
+
49
+ test('build() should rebuild the board', () => {
50
+ chessboard.build();
51
+ expect(chessboard.fen()).toBe('rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1');
52
+ });
53
+
54
+ test('clear() should clear the board', () => {
55
+ chessboard.clear();
56
+ expect(chessboard.fen()).toBe('8/8/8/8/8/8/8/8 w - - 0 1');
57
+ });
58
+
59
+ test('insert() should insert a piece on the given square', () => {
60
+ chessboard.insert('e4', 'qw');
61
+ expect(chessboard.get('e4')).toBe('qw');
62
+ });
63
+
64
+ test('isGameOver() should return the game over status', () => {
65
+ chessboard.position('default');
66
+ chessboard.move('e2e4');
67
+ chessboard.move('e7e5');
68
+ chessboard.move('d1h5');
69
+ chessboard.move('b8c6');
70
+ chessboard.move('f1c4');
71
+ chessboard.move('g8f6');
72
+ chessboard.move('h5f7');
73
+ expect(chessboard.isGameOver()).toBe('w');
74
+ });
75
+
76
+ test('orientation() should set the board orientation', () => {
77
+ chessboard.orientation('b');
78
+ expect(chessboard.getOrientation()).toBe('b');
79
+ });
80
+
81
+ test('resize() should resize the board', () => {
82
+ chessboard.resize(500);
83
+ expect(document.documentElement.style.getPropertyValue('--dimBoard')).toBe('500px');
84
+ });
85
+
86
+ test('destroy() should destroy the board', () => {
87
+ chessboard.destroy();
88
+ expect(chessboard.board).toBeNull();
89
+ });
90
+
91
+ test('remove() should remove a piece from the given square', () => {
92
+ chessboard.remove('e2');
93
+ expect(chessboard.get('e2')).toBeNull();
94
+ });
95
+
96
+ test('piece() should return the piece on the given square', () => {
97
+ expect(chessboard.piece('e2')).toBe('pw');
98
+ });
99
+
100
+ test('highlight() should highlight the given square', () => {
101
+ chessboard.highlight('e2');
102
+ expect(chessboard.squares['e2'].element.classList.contains('highlighted')).toBe(true);
103
+ });
104
+
105
+ test('dehighlight() should dehighlight the given square', () => {
106
+ chessboard.highlight('e2');
107
+ chessboard.dehighlight('e2');
108
+ expect(chessboard.squares['e2'].element.classList.contains('highlighted')).toBe(false);
109
+ });
110
+
111
+ test('playerTurn() should return true if it is the player turn', () => {
112
+ expect(chessboard.playerTurn()).toBe(true);
113
+ });
114
+
115
+ test('isWhiteOriented() should return true if the board is oriented for white', () => {
116
+ expect(chessboard.isWhiteOriented()).toBe(true);
117
+ });
118
+
119
+ test('getSquareID() should return the correct square ID', () => {
120
+ expect(chessboard.getSquareID(0, 0)).toBe('a8');
121
+ expect(chessboard.getSquareID(7, 7)).toBe('h1');
122
+ });
123
+
124
+ test('removeSquares() should remove all squares from the board', () => {
125
+ chessboard.removeSquares();
126
+ expect(Object.keys(chessboard.squares).length).toBe(0);
127
+ });
128
+ });