From 3b38c100452c38ff0de8b993e574a6968609c934 Mon Sep 17 00:00:00 2001 From: VVestin Date: Sun, 19 Nov 2023 23:04:16 +0000 Subject: [PATCH 1/4] Add state.selectedToDrop This represents a selected piece outside the board that can be dropped. --- src/board.ts | 26 +++++++++++++++++++++++++- src/drag.ts | 17 ++++++++++++++++- src/state.ts | 4 ++++ 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/board.ts b/src/board.ts index b3255ecd..9941b7b7 100644 --- a/src/board.ts +++ b/src/board.ts @@ -164,8 +164,9 @@ export function userMove(state: HeadlessState, orig: cg.Key, dest: cg.Key): bool return false; } -export function dropNewPiece(state: HeadlessState, orig: cg.Key, dest: cg.Key, force?: boolean): void { +export function dropNewPiece(state: HeadlessState, orig: cg.Key, dest: cg.Key, force?: boolean): boolean { const piece = state.pieces.get(orig); + let dropped = false; if (piece && (canDrop(state, orig, dest) || force)) { state.pieces.delete(orig); baseNewPiece(state, piece, dest, force); @@ -173,6 +174,8 @@ export function dropNewPiece(state: HeadlessState, orig: cg.Key, dest: cg.Key, f premove: false, predrop: false, }); + + dropped = true; } else if (piece && canPredrop(state, orig, dest)) { setPredrop(state, piece.role, dest); } else { @@ -181,6 +184,19 @@ export function dropNewPiece(state: HeadlessState, orig: cg.Key, dest: cg.Key, f } state.pieces.delete(orig); unselect(state); + return dropped; +} + +export function selectNewPieceToDrop( + state: HeadlessState, + piece: cg.Piece, + originTarget: EventTarget | null, +): void { + if (state.selected || state.selectedToDrop) unselect(state); + callUserFunction(state.events.select, 'a0'); + (originTarget as HTMLElement).classList.add('selected-pocket'); + + state.selectedToDrop = { piece, originTarget }; } export function selectSquare(state: HeadlessState, key: cg.Key, force?: boolean): void { @@ -197,6 +213,10 @@ export function selectSquare(state: HeadlessState, key: cg.Key, force?: boolean) } } } + if (state.selectedToDrop) { + state.pieces.set('a0', state.selectedToDrop.piece); + if (dropNewPiece(state, 'a0', key)) return; + } if ( (state.selectable.enabled || state.draggable.enabled) && (isMovable(state, key) || isPremovable(state, key)) @@ -217,6 +237,10 @@ export function setSelected(state: HeadlessState, key: cg.Key): void { } export function unselect(state: HeadlessState): void { + if (state.selectedToDrop) { + (state.selectedToDrop.originTarget as HTMLElement).classList.remove('selected-pocket'); + state.selectedToDrop = undefined; + } state.selected = undefined; state.premovable.dests = undefined; state.hold.cancel(); diff --git a/src/drag.ts b/src/drag.ts index fe3ce7ab..765586bb 100644 --- a/src/drag.ts +++ b/src/drag.ts @@ -15,6 +15,7 @@ export interface DragCurrent { newPiece?: boolean; // it it a new piece from outside the board force?: boolean; // can the new piece replace an existing one (editor) previouslySelected?: cg.Key; + previouslySelectedToDrop?: { piece: cg.Piece; originTarget: EventTarget | null }; originTarget: EventTarget | null; keyHasChanged: boolean; // whether the drag has left the orig key } @@ -95,6 +96,13 @@ function pieceCloseTo(s: State, pos: cg.NumberPair): boolean { } export function dragNewPiece(s: State, piece: cg.Piece, e: cg.MouchEvent, force?: boolean): void { + const previouslySelectedToDrop = s.selectedToDrop; + board.selectNewPieceToDrop(s, piece, e.target); + if (!s.draggable.enabled) { + if (previouslySelectedToDrop?.originTarget === s.selectedToDrop?.originTarget) board.unselect(s); + return; + } + const key: cg.Key = 'a0'; s.pieces.set(key, piece); s.dom.redraw(); @@ -112,6 +120,7 @@ export function dragNewPiece(s: State, piece: cg.Piece, e: cg.MouchEvent, force? newPiece: true, force: !!force, keyHasChanged: false, + previouslySelectedToDrop, }; processDrag(s); } @@ -186,7 +195,13 @@ export function end(s: State, e: cg.MouchEvent): void { s.pieces.delete(cur.orig); board.callUserFunction(s.events.change); } - if ((cur.orig === cur.previouslySelected || cur.keyHasChanged) && (cur.orig === dest || !dest)) + if ( + (cur.orig === cur.previouslySelected || cur.keyHasChanged) && + (cur.orig === dest || !dest) && + (!cur.newPiece || + e.target !== cur.originTarget || + (cur.previouslySelectedToDrop && cur.previouslySelectedToDrop.originTarget === e.target)) + ) board.unselect(s); else if (!s.selectable.enabled) board.unselect(s); diff --git a/src/state.ts b/src/state.ts index e91ac983..4753f1e3 100644 --- a/src/state.ts +++ b/src/state.ts @@ -12,6 +12,10 @@ export interface HeadlessState { check?: cg.Key; // square currently in check "a2" lastMove?: cg.Key[]; // squares part of the last move ["c3"; "c4"] selected?: cg.Key; // square currently selected "a1" + selectedToDrop?: { // piece currently selected to drop + piece: cg.Piece, + originTarget: EventTarget | null, + } coordinates: boolean; // include coords attributes ranksPosition: cg.RanksPosition; // position ranks on either side. left | right autoCastle: boolean; // immediately complete the castle by moving the rook after king move From d59b4c78a24d5fd2069507b1578b29188cd9e31a Mon Sep 17 00:00:00 2001 From: VVestin Date: Sun, 19 Nov 2023 23:10:32 +0000 Subject: [PATCH 2/4] Add demo board with droppable pieces --- demo.html | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/demo.html b/demo.html index 41ec3fc7..8ec2d4ea 100644 --- a/demo.html +++ b/demo.html @@ -23,6 +23,15 @@ height: 500px; } + .selected-pocket { + background-color: rgba(20, 85, 30, 0.5); + } + + #pocket { + display: flex; + flex-direction: row; + } + cg-board { background-color: #bfcfdd; } @@ -30,6 +39,7 @@ @@ -98,5 +122,29 @@ board with fixed arrows + labels
+
+ board with droppable pieces +
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+
From af9ac9a3979abdb3f36c47e1b425f3cb1e299cc3 Mon Sep 17 00:00:00 2001 From: VVestin Date: Mon, 20 Nov 2023 02:17:20 +0000 Subject: [PATCH 3/4] Change name of css class to selected-to-drop --- demo.html | 2 +- src/board.ts | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/demo.html b/demo.html index 8ec2d4ea..7d033733 100644 --- a/demo.html +++ b/demo.html @@ -23,7 +23,7 @@ height: 500px; } - .selected-pocket { + .selected-to-drop { background-color: rgba(20, 85, 30, 0.5); } diff --git a/src/board.ts b/src/board.ts index 9941b7b7..a29e8f2d 100644 --- a/src/board.ts +++ b/src/board.ts @@ -194,8 +194,7 @@ export function selectNewPieceToDrop( ): void { if (state.selected || state.selectedToDrop) unselect(state); callUserFunction(state.events.select, 'a0'); - (originTarget as HTMLElement).classList.add('selected-pocket'); - + (originTarget as HTMLElement).classList.add('selected-to-drop'); state.selectedToDrop = { piece, originTarget }; } @@ -238,7 +237,7 @@ export function setSelected(state: HeadlessState, key: cg.Key): void { export function unselect(state: HeadlessState): void { if (state.selectedToDrop) { - (state.selectedToDrop.originTarget as HTMLElement).classList.remove('selected-pocket'); + (state.selectedToDrop.originTarget as HTMLElement).classList.remove('selected-to-drop'); state.selectedToDrop = undefined; } state.selected = undefined; From 96d94c6d7a23b8b0a6e402088106cf09778e068a Mon Sep 17 00:00:00 2001 From: VVestin Date: Mon, 20 Nov 2023 02:38:51 +0000 Subject: [PATCH 4/4] Fix styling issue (run prettier) --- src/state.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/state.ts b/src/state.ts index 4753f1e3..dd41f535 100644 --- a/src/state.ts +++ b/src/state.ts @@ -12,10 +12,11 @@ export interface HeadlessState { check?: cg.Key; // square currently in check "a2" lastMove?: cg.Key[]; // squares part of the last move ["c3"; "c4"] selected?: cg.Key; // square currently selected "a1" - selectedToDrop?: { // piece currently selected to drop - piece: cg.Piece, - originTarget: EventTarget | null, - } + selectedToDrop?: { + // piece currently selected to drop + piece: cg.Piece; + originTarget: EventTarget | null; + }; coordinates: boolean; // include coords attributes ranksPosition: cg.RanksPosition; // position ranks on either side. left | right autoCastle: boolean; // immediately complete the castle by moving the rook after king move