cm-chessboard 3.17.8 → 3.18.1
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/examples/enable-input.html +1 -0
- package/examples/validate-moves.html +15 -2
- package/package.json +1 -1
- package/src/cm-chessboard/Chessboard.js +25 -37
- package/src/cm-chessboard/ChessboardView.js +18 -18
- package/src/cm-chessboard/ChessboardViewAccessible.js +68 -19
- package/test/TestBoard.js +1 -1
|
@@ -7,13 +7,25 @@
|
|
|
7
7
|
<link rel="stylesheet" href="styles/examples.css"/>
|
|
8
8
|
<link rel="stylesheet" href="../assets/styles/cm-chessboard.css"/>
|
|
9
9
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/chess.js/0.10.2/chess.js"></script>
|
|
10
|
+
<style>
|
|
11
|
+
.visually-hidden {
|
|
12
|
+
position: absolute;
|
|
13
|
+
left: -10000px;
|
|
14
|
+
top: auto;
|
|
15
|
+
width: 1px;
|
|
16
|
+
height: 1px;
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
}
|
|
19
|
+
</style>
|
|
10
20
|
</head>
|
|
11
21
|
<body>
|
|
12
|
-
<h1
|
|
13
|
-
<
|
|
22
|
+
<h1>Example: Input enabled, move validation with chess.js</h1>
|
|
23
|
+
<a href="../">Back to the cm-chessboard overview</a>
|
|
14
24
|
<p>Input enabled for white. <a href="https://github.com/jhlywa/chess.js">chess.js</a> does the validation and answers
|
|
15
25
|
with random moves.</p>
|
|
26
|
+
<h2 class="visually-hidden">The Board</h2>
|
|
16
27
|
<div class="board" id="board"></div>
|
|
28
|
+
<h2 class="visually-hidden">The Sourcecode of the example</h2>
|
|
17
29
|
<pre>
|
|
18
30
|
import {INPUT_EVENT_TYPE, COLOR, Chessboard, MARKER_TYPE} from "../src/cm-chessboard/Chessboard.js"
|
|
19
31
|
|
|
@@ -105,6 +117,7 @@ board.enableMoveInput(inputHandler, COLOR.white)
|
|
|
105
117
|
|
|
106
118
|
const board = new Chessboard(document.getElementById("board"), {
|
|
107
119
|
position: chess.fen(),
|
|
120
|
+
accessible: true,
|
|
108
121
|
// animationDuration: 2000,
|
|
109
122
|
sprite: {url: "../assets/images/chessboard-sprite-staunty.svg"},
|
|
110
123
|
style: {moveFromMarker: undefined, moveToMarker: undefined}, // disable standard markers
|
package/package.json
CHANGED
|
@@ -41,11 +41,12 @@ export const FEN_EMPTY_POSITION = "8/8/8/8/8/8/8/8"
|
|
|
41
41
|
|
|
42
42
|
export class Chessboard {
|
|
43
43
|
|
|
44
|
-
constructor(
|
|
45
|
-
if (!
|
|
46
|
-
throw new Error("container element is " +
|
|
44
|
+
constructor(context, props = {}) {
|
|
45
|
+
if (!context) {
|
|
46
|
+
throw new Error("container element is " + context)
|
|
47
47
|
}
|
|
48
|
-
this.
|
|
48
|
+
this.context = context
|
|
49
|
+
this.id = (Math.random() + 1).toString(36).substr(2, 6)
|
|
49
50
|
let defaultProps = {
|
|
50
51
|
position: "empty", // set as fen, "start" or "empty"
|
|
51
52
|
orientation: COLOR.white, // white on bottom
|
|
@@ -57,8 +58,6 @@ export class Chessboard {
|
|
|
57
58
|
aspectRatio: 1, // height/width. Set to `undefined`, if you want to define it only in the css.
|
|
58
59
|
moveFromMarker: MARKER_TYPE.frame, // the marker used to mark the start square
|
|
59
60
|
moveToMarker: MARKER_TYPE.frame, // the marker used to mark the square where the figure is moving to
|
|
60
|
-
moveMarker: MARKER_TYPE.frame, // deprecated => moveFromMarker // TODO remove in future
|
|
61
|
-
hoverMarker: MARKER_TYPE.frame // deprecated => moveToMarker // TODO remove in future
|
|
62
61
|
},
|
|
63
62
|
responsive: true, // resizes the board based on element size
|
|
64
63
|
animationDuration: 300, // pieces animation duration in milliseconds
|
|
@@ -79,31 +78,20 @@ export class Chessboard {
|
|
|
79
78
|
if (props.style) {
|
|
80
79
|
Object.assign(this.props.style, props.style)
|
|
81
80
|
}
|
|
82
|
-
if(this.props.style.moveMarker !== MARKER_TYPE.frame) { // TODO remove in future
|
|
83
|
-
console.warn("this.props.style.moveMarker is deprecated, use this.props.style.moveFromMarker")
|
|
84
|
-
this.props.style.moveFromMarker = this.props.style.moveMarker
|
|
85
|
-
}
|
|
86
|
-
if(this.props.style.hoverMarker !== MARKER_TYPE.frame) { // TODO remove in future
|
|
87
|
-
console.warn("this.props.style.hoverMarker is deprecated, use this.props.style.moveToMarker")
|
|
88
|
-
this.props.style.moveToMarker = this.props.style.hoverMarker
|
|
89
|
-
}
|
|
90
81
|
if (this.props.style.aspectRatio) {
|
|
91
|
-
this.
|
|
82
|
+
this.context.style.height = (this.context.offsetWidth * this.props.style.aspectRatio) + "px"
|
|
92
83
|
}
|
|
93
84
|
this.state = new ChessboardState()
|
|
85
|
+
if (this.props.position === "start") {
|
|
86
|
+
this.state.setPosition(FEN_START_POSITION)
|
|
87
|
+
} else if (this.props.position === "empty" || this.props.position === undefined) {
|
|
88
|
+
this.state.setPosition(FEN_EMPTY_POSITION)
|
|
89
|
+
} else {
|
|
90
|
+
this.state.setPosition(this.props.position)
|
|
91
|
+
}
|
|
94
92
|
this.state.orientation = this.props.orientation
|
|
95
|
-
|
|
96
93
|
const viewType = this.props.accessible ? ChessboardViewAccessible : ChessboardView
|
|
97
|
-
this.view = new viewType(this
|
|
98
|
-
if (this.props.position === "start") {
|
|
99
|
-
this.state.setPosition(FEN_START_POSITION)
|
|
100
|
-
} else if (this.props.position === "empty" || this.props.position === undefined) {
|
|
101
|
-
this.state.setPosition(FEN_EMPTY_POSITION)
|
|
102
|
-
} else {
|
|
103
|
-
this.state.setPosition(this.props.position)
|
|
104
|
-
}
|
|
105
|
-
view.redraw()
|
|
106
|
-
})
|
|
94
|
+
this.view = new viewType(this)
|
|
107
95
|
}
|
|
108
96
|
|
|
109
97
|
// API //
|
|
@@ -211,9 +199,9 @@ export class Chessboard {
|
|
|
211
199
|
this.view = undefined
|
|
212
200
|
this.state = undefined
|
|
213
201
|
if (this.squareSelectListener) {
|
|
214
|
-
this.
|
|
215
|
-
this.
|
|
216
|
-
this.
|
|
202
|
+
this.context.removeEventListener("contextmenu", this.squareSelectListener)
|
|
203
|
+
this.context.removeEventListener("mouseup", this.squareSelectListener)
|
|
204
|
+
this.context.removeEventListener("touchend", this.squareSelectListener)
|
|
217
205
|
}
|
|
218
206
|
}
|
|
219
207
|
|
|
@@ -260,20 +248,20 @@ export class Chessboard {
|
|
|
260
248
|
square: SQUARE_COORDINATES[index]
|
|
261
249
|
})
|
|
262
250
|
}
|
|
263
|
-
this.
|
|
264
|
-
this.
|
|
265
|
-
this.
|
|
251
|
+
this.context.addEventListener("contextmenu", this.squareSelectListener)
|
|
252
|
+
this.context.addEventListener("mouseup", this.squareSelectListener)
|
|
253
|
+
this.context.addEventListener("touchend", this.squareSelectListener)
|
|
266
254
|
this.state.squareSelectEnabled = true
|
|
267
|
-
this.view.
|
|
255
|
+
this.view.visualizeInputState()
|
|
268
256
|
}
|
|
269
257
|
|
|
270
258
|
disableSquareSelect() {
|
|
271
|
-
this.
|
|
272
|
-
this.
|
|
273
|
-
this.
|
|
259
|
+
this.context.removeEventListener("contextmenu", this.squareSelectListener)
|
|
260
|
+
this.context.removeEventListener("mouseup", this.squareSelectListener)
|
|
261
|
+
this.context.removeEventListener("touchend", this.squareSelectListener)
|
|
274
262
|
this.squareSelectListener = undefined
|
|
275
263
|
this.state.squareSelectEnabled = false
|
|
276
|
-
this.view.
|
|
264
|
+
this.view.visualizeInputState()
|
|
277
265
|
}
|
|
278
266
|
|
|
279
267
|
}
|
|
@@ -60,7 +60,7 @@ export const SQUARE_COORDINATES = [
|
|
|
60
60
|
|
|
61
61
|
export class ChessboardView {
|
|
62
62
|
|
|
63
|
-
constructor(chessboard
|
|
63
|
+
constructor(chessboard) {
|
|
64
64
|
this.animationRunning = false
|
|
65
65
|
this.currentAnimation = undefined
|
|
66
66
|
this.chessboard = chessboard
|
|
@@ -80,7 +80,7 @@ export class ChessboardView {
|
|
|
80
80
|
this.resizeObserver = new ResizeObserver(() => {
|
|
81
81
|
this.handleResize()
|
|
82
82
|
})
|
|
83
|
-
this.resizeObserver.observe(this.chessboard.
|
|
83
|
+
this.resizeObserver.observe(this.chessboard.context)
|
|
84
84
|
} else {
|
|
85
85
|
this.resizeListener = this.handleResize.bind(this)
|
|
86
86
|
window.addEventListener("resize", this.resizeListener)
|
|
@@ -88,15 +88,15 @@ export class ChessboardView {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
this.pointerDownListener = this.pointerDownHandler.bind(this)
|
|
91
|
-
this.chessboard.
|
|
92
|
-
this.chessboard.
|
|
91
|
+
this.chessboard.context.addEventListener("mousedown", this.pointerDownListener)
|
|
92
|
+
this.chessboard.context.addEventListener("touchstart", this.pointerDownListener)
|
|
93
93
|
|
|
94
94
|
this.createSvgAndGroups()
|
|
95
95
|
this.updateMetrics()
|
|
96
|
-
callbackAfterCreation(this)
|
|
97
96
|
if (chessboard.props.responsive) {
|
|
98
97
|
this.handleResize()
|
|
99
98
|
}
|
|
99
|
+
this.redraw()
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
pointerDownHandler(e) {
|
|
@@ -106,13 +106,13 @@ export class ChessboardView {
|
|
|
106
106
|
destroy() {
|
|
107
107
|
this.moveInput.destroy()
|
|
108
108
|
if (this.resizeObserver) {
|
|
109
|
-
this.resizeObserver.unobserve(this.chessboard.
|
|
109
|
+
this.resizeObserver.unobserve(this.chessboard.context)
|
|
110
110
|
}
|
|
111
111
|
if (this.resizeListener) {
|
|
112
112
|
window.removeEventListener("resize", this.resizeListener)
|
|
113
113
|
}
|
|
114
|
-
this.chessboard.
|
|
115
|
-
this.chessboard.
|
|
114
|
+
this.chessboard.context.removeEventListener("mousedown", this.pointerDownListener)
|
|
115
|
+
this.chessboard.context.removeEventListener("touchstart", this.pointerDownListener)
|
|
116
116
|
Svg.removeElement(this.svg)
|
|
117
117
|
this.animationQueue = []
|
|
118
118
|
if (this.currentAnimation) {
|
|
@@ -142,7 +142,7 @@ export class ChessboardView {
|
|
|
142
142
|
if (this.svg) {
|
|
143
143
|
Svg.removeElement(this.svg)
|
|
144
144
|
}
|
|
145
|
-
this.svg = Svg.createSvg(this.chessboard.
|
|
145
|
+
this.svg = Svg.createSvg(this.chessboard.context)
|
|
146
146
|
let description = document.createElement("description")
|
|
147
147
|
description.innerText = "Chessboard"
|
|
148
148
|
description.id = "svg-description"
|
|
@@ -159,8 +159,8 @@ export class ChessboardView {
|
|
|
159
159
|
}
|
|
160
160
|
|
|
161
161
|
updateMetrics() {
|
|
162
|
-
this.width = this.chessboard.
|
|
163
|
-
this.height = this.chessboard.
|
|
162
|
+
this.width = this.chessboard.context.clientWidth
|
|
163
|
+
this.height = this.chessboard.context.clientHeight
|
|
164
164
|
if (this.chessboard.props.style.borderType === BORDER_TYPE.frame) {
|
|
165
165
|
this.borderSize = this.width / 25
|
|
166
166
|
} else if (this.chessboard.props.style.borderType === BORDER_TYPE.thin) {
|
|
@@ -179,10 +179,10 @@ export class ChessboardView {
|
|
|
179
179
|
|
|
180
180
|
handleResize() {
|
|
181
181
|
if (this.chessboard.props.style.aspectRatio) {
|
|
182
|
-
this.chessboard.
|
|
182
|
+
this.chessboard.context.style.height = (this.chessboard.context.clientWidth * this.chessboard.props.style.aspectRatio) + "px"
|
|
183
183
|
}
|
|
184
|
-
if (this.chessboard.
|
|
185
|
-
this.chessboard.
|
|
184
|
+
if (this.chessboard.context.clientWidth !== this.width ||
|
|
185
|
+
this.chessboard.context.clientHeight !== this.height) {
|
|
186
186
|
this.updateMetrics()
|
|
187
187
|
this.redraw()
|
|
188
188
|
}
|
|
@@ -194,7 +194,7 @@ export class ChessboardView {
|
|
|
194
194
|
this.drawBoard()
|
|
195
195
|
this.drawCoordinates()
|
|
196
196
|
this.drawMarkers()
|
|
197
|
-
this.
|
|
197
|
+
this.visualizeInputState()
|
|
198
198
|
this.drawPieces(this.chessboard.state.squares)
|
|
199
199
|
}
|
|
200
200
|
|
|
@@ -413,7 +413,7 @@ export class ChessboardView {
|
|
|
413
413
|
}
|
|
414
414
|
this.chessboard.state.inputEnabled = true
|
|
415
415
|
this.moveInputCallback = eventHandler
|
|
416
|
-
this.
|
|
416
|
+
this.visualizeInputState()
|
|
417
417
|
}
|
|
418
418
|
|
|
419
419
|
disableMoveInput() {
|
|
@@ -421,7 +421,7 @@ export class ChessboardView {
|
|
|
421
421
|
this.chessboard.state.inputBlackEnabled = false
|
|
422
422
|
this.chessboard.state.inputEnabled = false
|
|
423
423
|
this.moveInputCallback = undefined
|
|
424
|
-
this.
|
|
424
|
+
this.visualizeInputState()
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
// callbacks //
|
|
@@ -465,7 +465,7 @@ export class ChessboardView {
|
|
|
465
465
|
|
|
466
466
|
// Helpers //
|
|
467
467
|
|
|
468
|
-
|
|
468
|
+
visualizeInputState() {
|
|
469
469
|
if (this.chessboard.state) { // fix https://github.com/shaack/cm-chessboard/issues/47
|
|
470
470
|
if (this.chessboard.state.inputWhiteEnabled || this.chessboard.state.inputBlackEnabled || this.chessboard.state.squareSelectEnabled) {
|
|
471
471
|
this.boardGroup.setAttribute("class", "board input-enabled")
|
|
@@ -7,17 +7,28 @@ import {ChessboardView, renderPieceTitle} from "./ChessboardView.js"
|
|
|
7
7
|
import {COLOR} from "./Chessboard.js"
|
|
8
8
|
import {piecesTranslations} from "./ChessboardView.js"
|
|
9
9
|
|
|
10
|
-
let count = 0
|
|
11
|
-
|
|
12
|
-
|
|
13
10
|
const hlTranslations = {
|
|
14
|
-
en: {
|
|
15
|
-
pieces_lists: "Pieces lists",
|
|
16
|
-
board_as_table: "Chessboard as table"
|
|
17
|
-
},
|
|
18
11
|
de: {
|
|
19
12
|
pieces_lists: "Figurenlisten",
|
|
20
|
-
board_as_table: "Schachbrett als Tabelle"
|
|
13
|
+
board_as_table: "Schachbrett als Tabelle",
|
|
14
|
+
move_piece: "Figur bewegen",
|
|
15
|
+
from: "von",
|
|
16
|
+
to: "nach",
|
|
17
|
+
move: "bewegen",
|
|
18
|
+
input_white_enabled: "Eingabe Weiß aktiviert",
|
|
19
|
+
input_black_enabled: "Eingabe Schwarz aktiviert",
|
|
20
|
+
input_disabled: "Eingabe deaktiviert"
|
|
21
|
+
},
|
|
22
|
+
en: {
|
|
23
|
+
pieces_lists: "Pieces lists",
|
|
24
|
+
board_as_table: "Chessboard as table",
|
|
25
|
+
move_piece: "Move piece",
|
|
26
|
+
from: "from",
|
|
27
|
+
to: "to",
|
|
28
|
+
move: "move",
|
|
29
|
+
input_white_enabled: "Input white enabled",
|
|
30
|
+
input_black_enabled: "Input black enabled",
|
|
31
|
+
input_disabled: "Input disabled"
|
|
21
32
|
}
|
|
22
33
|
}
|
|
23
34
|
|
|
@@ -32,19 +43,58 @@ export class ChessboardViewAccessible extends ChessboardView {
|
|
|
32
43
|
this.translations = piecesTranslations
|
|
33
44
|
this.t = this.translations[this.lang]
|
|
34
45
|
this.th = hlTranslations[this.lang]
|
|
35
|
-
|
|
36
|
-
this.
|
|
37
|
-
|
|
38
|
-
this.
|
|
46
|
+
|
|
47
|
+
this.accessibleContainer = this.createElement(`<div class="cm-chessboard-content visually-hidden"></div>`)
|
|
48
|
+
|
|
49
|
+
this.movePieceFormContainer = this.createElement(`<div><h3>${this.th.move_piece}</h3><form>
|
|
50
|
+
<label for="move_piece_input_from_${chessboard.id}">${this.th.from}</label><input class="input-from" type="text" size="2" id="move_piece_input_from_${chessboard.id}"/>
|
|
51
|
+
<label for="move_piece_input_to_${chessboard.id}">${this.th.to}</label><input class="input-to" type="text" size="2" id="move_piece_input_to_${chessboard.id}"/>
|
|
52
|
+
<button type="button" class="button-move">${this.th.move}</button>
|
|
53
|
+
</form><div class="input-status" aria-live="polite"></div></div>`)
|
|
54
|
+
this.inputFrom = this.movePieceFormContainer.querySelector(".input-from")
|
|
55
|
+
this.inputTo = this.movePieceFormContainer.querySelector(".input-to")
|
|
56
|
+
this.moveButton = this.movePieceFormContainer.querySelector(".button-move")
|
|
57
|
+
this.moveButton.addEventListener("click", () => {
|
|
58
|
+
this.chessboard.movePiece(this.inputFrom.value, this.inputTo.value, true)
|
|
59
|
+
})
|
|
60
|
+
this.accessibleContainer.appendChild(this.movePieceFormContainer)
|
|
61
|
+
|
|
62
|
+
this.boardAsTableContainer = this.createElement(`<div><h3>${this.th.board_as_table}</h3><div class="table"></div></div>`)
|
|
39
63
|
this.boardAsTable = this.boardAsTableContainer.querySelector(".table")
|
|
40
|
-
this.
|
|
64
|
+
this.accessibleContainer.appendChild(this.boardAsTableContainer)
|
|
65
|
+
|
|
66
|
+
this.piecesListContainer = this.createElement(`<div><h3>${this.th.pieces_lists}</h3><div class="list"></div></div>`)
|
|
67
|
+
this.piecesList = this.piecesListContainer.querySelector(".list")
|
|
68
|
+
this.accessibleContainer.appendChild(this.piecesListContainer)
|
|
69
|
+
|
|
70
|
+
this.chessboard.context.appendChild(this.accessibleContainer)
|
|
71
|
+
this.updateFormInputs()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
visualizeInputState() {
|
|
75
|
+
super.visualizeInputState()
|
|
76
|
+
this.updateFormInputs()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
updateFormInputs() {
|
|
80
|
+
if (this.inputFrom) {
|
|
81
|
+
if (this.chessboard.state.inputWhiteEnabled || this.chessboard.state.inputBlackEnabled) {
|
|
82
|
+
this.inputFrom.disabled = false
|
|
83
|
+
this.inputTo.disabled = false
|
|
84
|
+
this.moveButton.disabled = false
|
|
85
|
+
} else {
|
|
86
|
+
this.inputFrom.disabled = true
|
|
87
|
+
this.inputTo.disabled = true
|
|
88
|
+
this.moveButton.disabled = true
|
|
89
|
+
}
|
|
90
|
+
}
|
|
41
91
|
}
|
|
42
92
|
|
|
43
93
|
drawPieces(squares = this.chessboard.state.squares) {
|
|
44
94
|
super.drawPieces(squares)
|
|
45
95
|
setTimeout(() => {
|
|
46
|
-
this.redrawPiecesLists()
|
|
47
96
|
this.redrawBoardAsTable()
|
|
97
|
+
this.redrawPiecesLists()
|
|
48
98
|
})
|
|
49
99
|
}
|
|
50
100
|
|
|
@@ -59,12 +109,11 @@ export class ChessboardViewAccessible extends ChessboardView {
|
|
|
59
109
|
listB += `<li class="list-inline-item">${renderPieceTitle(this.lang, piece.name)} ${piece.position}</li>`
|
|
60
110
|
}
|
|
61
111
|
}
|
|
62
|
-
count++
|
|
63
112
|
this.piecesList.innerHTML = `
|
|
64
|
-
<h4 id="
|
|
65
|
-
<ul aria-labelledby="
|
|
66
|
-
<h4 id="
|
|
67
|
-
<ul aria-labelledby="
|
|
113
|
+
<h4 id="white_${this.chessboard.id}">${this.t.colors_long.w}</h4>
|
|
114
|
+
<ul aria-labelledby="white_${this.chessboard.id}" class="list-inline">${listW}</ul>
|
|
115
|
+
<h4 id="black_${this.chessboard.id}">${this.t.colors_long.b}</h4>
|
|
116
|
+
<ul aria-labelledby="black_${this.chessboard.id}" class="list-inline">${listB}</ul>`
|
|
68
117
|
}
|
|
69
118
|
|
|
70
119
|
redrawBoardAsTable() {
|
package/test/TestBoard.js
CHANGED
|
@@ -23,7 +23,7 @@ describe("TestBoard", () => {
|
|
|
23
23
|
sprite: {url: "../assets/images/chessboard-sprite.svg"},
|
|
24
24
|
position: "start"
|
|
25
25
|
})
|
|
26
|
-
assert.equals(chessboard.
|
|
26
|
+
assert.equals(chessboard.context.childNodes.length, 1)
|
|
27
27
|
chessboard.destroy()
|
|
28
28
|
assert.equals(chessboard.state, undefined)
|
|
29
29
|
})
|