cm-chessboard 8.12.16 → 8.12.17
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 +3 -0
- package/package.json +1 -1
- package/src/view/ChessboardView.js +7 -2
- package/src/view/VisualMoveInput.js +10 -12
- package/test/TestVisualMoveInput.js +37 -0
package/README.md
CHANGED
|
@@ -207,6 +207,9 @@ The event has the following **`event.type`**:
|
|
|
207
207
|
Return `true` or `false` to validate the start square. `false` cancels the move.
|
|
208
208
|
- **`INPUT_EVENT_TYPE.validateMoveInput`**: To validate the users move input. `event.squareFrom` and `event.squareTo`
|
|
209
209
|
contain the coordinates. Return `true` or `false` to validate the move. `false` cancels the move.
|
|
210
|
+
`event.probe` is `true` when the target square still holds one of the mover's own pieces (e.g. clicking another own
|
|
211
|
+
piece, or a chess960 castling target). A falsy result then means "re-select that piece" rather than an illegal move,
|
|
212
|
+
so you can suppress illegal-move feedback when `event.probe` is set.
|
|
210
213
|
- **`INPUT_EVENT_TYPE.moveInputCanceled`**: The user canceled the move with clicking again on the start square, clicking
|
|
211
214
|
outside the board or right click.
|
|
212
215
|
- **`INPUT_EVENT_TYPE.moveInputFinished`**: Fired after the move was made, also when canceled.
|
package/package.json
CHANGED
|
@@ -410,13 +410,18 @@ export class ChessboardView {
|
|
|
410
410
|
this.chessboard.state.invokeExtensionPoints(EXTENSION_POINT.moveInput, data)
|
|
411
411
|
}
|
|
412
412
|
|
|
413
|
-
validateMoveInputCallback(squareFrom, squareTo) {
|
|
413
|
+
validateMoveInputCallback(squareFrom, squareTo, probe = false) {
|
|
414
414
|
const data = {
|
|
415
415
|
chessboard: this.chessboard,
|
|
416
416
|
type: INPUT_EVENT_TYPE.validateMoveInput,
|
|
417
417
|
squareFrom: squareFrom,
|
|
418
418
|
squareTo: squareTo,
|
|
419
|
-
piece: this.chessboard.getPiece(squareFrom)
|
|
419
|
+
piece: this.chessboard.getPiece(squareFrom),
|
|
420
|
+
// true when this is only a speculative check whether the clicked
|
|
421
|
+
// same-color piece is a legal target (e.g. chess960 castling). A
|
|
422
|
+
// falsy result then means "re-select this piece", not an illegal
|
|
423
|
+
// move, so consumers can suppress illegal-move feedback.
|
|
424
|
+
probe: probe
|
|
420
425
|
}
|
|
421
426
|
if (this.chessboard.state.moveInputCallback) {
|
|
422
427
|
data.moveInputCallbackResult = this.chessboard.state.moveInputCallback(data)
|
|
@@ -59,8 +59,8 @@ export class VisualMoveInput {
|
|
|
59
59
|
this.view.movingOverSquareCallback(fromSquare, toSquare)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
validateMoveInputCallback(fromSquare, toSquare) {
|
|
63
|
-
const result = this.view.validateMoveInputCallback(fromSquare, toSquare)
|
|
62
|
+
validateMoveInputCallback(fromSquare, toSquare, probe = false) {
|
|
63
|
+
const result = this.view.validateMoveInputCallback(fromSquare, toSquare, probe)
|
|
64
64
|
this.chessboard.state.moveInputProcess.resolve(result)
|
|
65
65
|
return result
|
|
66
66
|
}
|
|
@@ -298,8 +298,10 @@ export class VisualMoveInput {
|
|
|
298
298
|
const startPieceName = this.chessboard.getPiece(this.fromSquare)
|
|
299
299
|
const startPieceColor = startPieceName ? startPieceName.substring(0, 1) : null
|
|
300
300
|
if (color && startPieceColor === pieceColor) {
|
|
301
|
-
// added to allow chess960 castling
|
|
302
|
-
|
|
301
|
+
// added to allow chess960 castling. This is only a probe:
|
|
302
|
+
// a falsy result means the user re-selected another own
|
|
303
|
+
// piece, not that an illegal move was attempted.
|
|
304
|
+
const result = this.validateMoveInputCallback(this.fromSquare, square, true)
|
|
303
305
|
if(!result) {
|
|
304
306
|
this.moveInputCanceledCallback(this.fromSquare, square, MOVE_CANCELED_REASON.clickedAnotherPiece)
|
|
305
307
|
if (this.moveInputStartedCallback(square)) {
|
|
@@ -384,14 +386,10 @@ export class VisualMoveInput {
|
|
|
384
386
|
if (square) {
|
|
385
387
|
if (this.moveInputState === MOVE_INPUT_STATE.dragTo || this.moveInputState === MOVE_INPUT_STATE.clickDragTo) {
|
|
386
388
|
if (this.fromSquare === square) {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.setMoveInputState(MOVE_INPUT_STATE.reset)
|
|
392
|
-
} else {
|
|
393
|
-
this.setMoveInputState(MOVE_INPUT_STATE.clickTo, {square: square})
|
|
394
|
-
}
|
|
389
|
+
this.chessboard.state.position.setPiece(this.fromSquare, this.movedPiece)
|
|
390
|
+
this.view.setPieceVisibility(this.fromSquare)
|
|
391
|
+
this.moveInputCanceledCallback(square, null, MOVE_CANCELED_REASON.draggedBack)
|
|
392
|
+
this.setMoveInputState(MOVE_INPUT_STATE.reset)
|
|
395
393
|
} else {
|
|
396
394
|
this.setMoveInputState(MOVE_INPUT_STATE.moveDone, {square: square})
|
|
397
395
|
}
|
|
@@ -6,10 +6,12 @@
|
|
|
6
6
|
|
|
7
7
|
import {describe, it, assert} from "../node_modules/teevi/src/teevi.js"
|
|
8
8
|
import {Chessboard} from "../src/Chessboard.js"
|
|
9
|
+
import {COLOR, INPUT_EVENT_TYPE} from "../src/view/ChessboardView.js"
|
|
9
10
|
import {FEN} from "../src/model/Position.js"
|
|
10
11
|
|
|
11
12
|
const STATE_WAIT_FOR_INPUT_START = "waitForInputStart"
|
|
12
13
|
const STATE_PIECE_CLICKED_THRESHOLD = "pieceClickedThreshold"
|
|
14
|
+
const STATE_CLICK_TO = "clickTo"
|
|
13
15
|
|
|
14
16
|
describe("TestVisualMoveInput", () => {
|
|
15
17
|
|
|
@@ -37,4 +39,39 @@ describe("TestVisualMoveInput", () => {
|
|
|
37
39
|
chessboard.destroy()
|
|
38
40
|
})
|
|
39
41
|
|
|
42
|
+
it("should mark the same-color reselect validation as a probe", async () => {
|
|
43
|
+
const chessboard = new Chessboard(document.getElementById("TestBoard"), {
|
|
44
|
+
assetsUrl: "../assets/",
|
|
45
|
+
position: FEN.start
|
|
46
|
+
})
|
|
47
|
+
let probeSeen
|
|
48
|
+
chessboard.enableMoveInput((event) => {
|
|
49
|
+
if (event.type === INPUT_EVENT_TYPE.validateMoveInput) {
|
|
50
|
+
probeSeen = event.probe
|
|
51
|
+
return false // reject -> this is a re-selection, not a real move
|
|
52
|
+
}
|
|
53
|
+
return true
|
|
54
|
+
}, COLOR.white)
|
|
55
|
+
const visualMoveInput = chessboard.view.visualMoveInput
|
|
56
|
+
|
|
57
|
+
// simulate an existing click-to-move selection of the white e2 pawn
|
|
58
|
+
// (moveInputStartedCallback sets up the internal moveInputProcess task)
|
|
59
|
+
visualMoveInput.moveInputStartedCallback("e2")
|
|
60
|
+
visualMoveInput.moveInputState = STATE_CLICK_TO
|
|
61
|
+
visualMoveInput.fromSquare = "e2"
|
|
62
|
+
|
|
63
|
+
// click another own (white) piece, the d1 queen -> chess960 probe branch
|
|
64
|
+
visualMoveInput.onPointerDown({
|
|
65
|
+
type: "touchstart",
|
|
66
|
+
target: {getAttribute: (name) => (name === "data-square" ? "d1" : null)},
|
|
67
|
+
touches: [{clientX: 100, clientY: 100}],
|
|
68
|
+
preventDefault: () => {}
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
assert.equal(probeSeen, true)
|
|
72
|
+
|
|
73
|
+
await new Promise((resolve) => setTimeout(resolve))
|
|
74
|
+
chessboard.destroy()
|
|
75
|
+
})
|
|
76
|
+
|
|
40
77
|
})
|