@alepot55/chessboardjs 2.2.1 → 2.2.2
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/.eslintrc.json +227 -0
- package/README.md +125 -401
- package/assets/themes/alepot/theme.json +42 -0
- package/assets/themes/default/theme.json +42 -0
- package/chessboard.bundle.js +708 -58
- package/config/jest.config.js +15 -0
- package/config/rollup.config.js +36 -0
- package/dist/chessboard.cjs.js +10690 -0
- package/dist/chessboard.css +228 -0
- package/dist/chessboard.esm.js +10621 -0
- package/dist/chessboard.iife.js +10696 -0
- package/dist/chessboard.umd.js +10696 -0
- package/jest.config.js +2 -7
- package/package.json +18 -3
- package/rollup.config.js +2 -11
- package/{chessboard.move.js → src/components/Move.js} +3 -3
- package/src/components/Piece.js +288 -0
- package/{chessboard.square.js → src/components/Square.js} +60 -7
- package/src/constants/index.js +15 -0
- package/src/constants/positions.js +62 -0
- package/src/core/Chessboard.js +1939 -0
- package/src/core/ChessboardConfig.js +458 -0
- package/src/core/ChessboardFactory.js +385 -0
- package/src/core/index.js +141 -0
- package/src/errors/ChessboardError.js +133 -0
- package/src/errors/index.js +15 -0
- package/src/errors/messages.js +189 -0
- package/src/index.js +103 -0
- package/src/services/AnimationService.js +180 -0
- package/src/services/BoardService.js +156 -0
- package/src/services/CoordinateService.js +355 -0
- package/src/services/EventService.js +955 -0
- package/src/services/MoveService.js +629 -0
- package/src/services/PieceService.js +312 -0
- package/src/services/PositionService.js +237 -0
- package/src/services/ValidationService.js +673 -0
- package/src/services/index.js +14 -0
- package/src/styles/animations.css +46 -0
- package/{chessboard.css → src/styles/board.css} +8 -4
- package/src/styles/index.css +4 -0
- package/src/styles/pieces.css +70 -0
- package/src/utils/animations.js +37 -0
- package/{chess.js → src/utils/chess.js} +16 -16
- package/src/utils/coordinates.js +62 -0
- package/src/utils/cross-browser.js +150 -0
- package/src/utils/logger.js +422 -0
- package/src/utils/performance.js +311 -0
- package/src/utils/validation.js +458 -0
- package/tests/unit/chessboard-config-animations.test.js +106 -0
- package/tests/unit/chessboard-robust.test.js +163 -0
- package/tests/unit/chessboard.test.js +183 -0
- package/chessboard.config.js +0 -147
- package/chessboard.js +0 -979
- package/chessboard.piece.js +0 -115
- package/test/chessboard.test.js +0 -128
- /package/{alepot_theme → assets/themes/alepot}/bb.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/bw.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/kb.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/kw.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/nb.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/nw.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/pb.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/pw.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/qb.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/qw.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/rb.svg +0 -0
- /package/{alepot_theme → assets/themes/alepot}/rw.svg +0 -0
- /package/{default_pieces → assets/themes/default}/bb.svg +0 -0
- /package/{default_pieces → assets/themes/default}/bw.svg +0 -0
- /package/{default_pieces → assets/themes/default}/kb.svg +0 -0
- /package/{default_pieces → assets/themes/default}/kw.svg +0 -0
- /package/{default_pieces → assets/themes/default}/nb.svg +0 -0
- /package/{default_pieces → assets/themes/default}/nw.svg +0 -0
- /package/{default_pieces → assets/themes/default}/pb.svg +0 -0
- /package/{default_pieces → assets/themes/default}/pw.svg +0 -0
- /package/{default_pieces → assets/themes/default}/qb.svg +0 -0
- /package/{default_pieces → assets/themes/default}/qw.svg +0 -0
- /package/{default_pieces → assets/themes/default}/rb.svg +0 -0
- /package/{default_pieces → assets/themes/default}/rw.svg +0 -0
- /package/{.babelrc → config/.babelrc} +0 -0
package/chessboard.bundle.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var Chessboard = (function () {
|
|
1
|
+
var Chessboard = (function (exports) {
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -1992,6 +1992,14 @@ var Chessboard = (function () {
|
|
|
1992
1992
|
'veryFast': 100
|
|
1993
1993
|
};
|
|
1994
1994
|
|
|
1995
|
+
const boolValues = {
|
|
1996
|
+
'true': true,
|
|
1997
|
+
'false': false,
|
|
1998
|
+
'none': false,
|
|
1999
|
+
1: true,
|
|
2000
|
+
0: false
|
|
2001
|
+
};
|
|
2002
|
+
|
|
1995
2003
|
const transitionFunctions = {
|
|
1996
2004
|
'ease': 'ease',
|
|
1997
2005
|
'linear': 'linear',
|
|
@@ -2023,7 +2031,7 @@ var Chessboard = (function () {
|
|
|
2023
2031
|
fadeTime: 'fast',
|
|
2024
2032
|
fadeAnimation: 'ease',
|
|
2025
2033
|
ratio: 0.9,
|
|
2026
|
-
piecesPath: '
|
|
2034
|
+
piecesPath: '../assets/themes/default',
|
|
2027
2035
|
onMove: () => true,
|
|
2028
2036
|
onMoveEnd: () => true,
|
|
2029
2037
|
onChange: () => true,
|
|
@@ -2113,11 +2121,26 @@ var Chessboard = (function () {
|
|
|
2113
2121
|
|
|
2114
2122
|
setBoolean(value) {
|
|
2115
2123
|
if (typeof value === 'boolean') return value;
|
|
2124
|
+
if (value in boolValues) return boolValues[value];
|
|
2116
2125
|
throw new Error('Invalid boolean value');
|
|
2117
2126
|
}
|
|
2118
2127
|
|
|
2119
2128
|
setTransitionFunction(value) {
|
|
2120
|
-
|
|
2129
|
+
// Handle boolean values - true means use default 'ease', false/null means no animation
|
|
2130
|
+
if (typeof value === 'boolean') {
|
|
2131
|
+
return value ? transitionFunctions['ease'] : null;
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
// Handle string values
|
|
2135
|
+
if (typeof value === 'string' && value in transitionFunctions) {
|
|
2136
|
+
return transitionFunctions[value];
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
// Handle null/undefined
|
|
2140
|
+
if (value === null || value === undefined) {
|
|
2141
|
+
return null;
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2121
2144
|
throw new Error('Invalid transition function');
|
|
2122
2145
|
}
|
|
2123
2146
|
}
|
|
@@ -2166,7 +2189,20 @@ var Chessboard = (function () {
|
|
|
2166
2189
|
}
|
|
2167
2190
|
|
|
2168
2191
|
fadeOut(duration, speed, transition_f) {
|
|
2169
|
-
performance.now();
|
|
2192
|
+
let start = performance.now();
|
|
2193
|
+
let opacity = 1;
|
|
2194
|
+
let piece = this;
|
|
2195
|
+
let fade = function () {
|
|
2196
|
+
let elapsed = performance.now() - start;
|
|
2197
|
+
opacity = 1 - transition_f(elapsed, duration, speed);
|
|
2198
|
+
piece.element.style.opacity = opacity;
|
|
2199
|
+
if (elapsed < duration) {
|
|
2200
|
+
requestAnimationFrame(fade);
|
|
2201
|
+
} else {
|
|
2202
|
+
piece.element.style.opacity = 0;
|
|
2203
|
+
}
|
|
2204
|
+
};
|
|
2205
|
+
fade();
|
|
2170
2206
|
}
|
|
2171
2207
|
|
|
2172
2208
|
setDrag(f) {
|
|
@@ -2279,6 +2315,9 @@ var Chessboard = (function () {
|
|
|
2279
2315
|
}
|
|
2280
2316
|
|
|
2281
2317
|
removePiece() {
|
|
2318
|
+
if (!this.piece) {
|
|
2319
|
+
return null;
|
|
2320
|
+
}
|
|
2282
2321
|
this.element.removeChild(this.piece.element);
|
|
2283
2322
|
const piece = this.piece;
|
|
2284
2323
|
this.piece = null;
|
|
@@ -2408,7 +2447,7 @@ var Chessboard = (function () {
|
|
|
2408
2447
|
class Move {
|
|
2409
2448
|
|
|
2410
2449
|
constructor(from, to, promotion = null, check = false) {
|
|
2411
|
-
this.piece = from.getPiece();
|
|
2450
|
+
this.piece = from ? from.getPiece() : null;
|
|
2412
2451
|
this.from = from;
|
|
2413
2452
|
this.to = to;
|
|
2414
2453
|
this.promotion = promotion;
|
|
@@ -2444,7 +2483,136 @@ var Chessboard = (function () {
|
|
|
2444
2483
|
|
|
2445
2484
|
}
|
|
2446
2485
|
|
|
2447
|
-
|
|
2486
|
+
/**
|
|
2487
|
+
* Performance utilities for smooth interactions
|
|
2488
|
+
*/
|
|
2489
|
+
|
|
2490
|
+
/**
|
|
2491
|
+
* Throttle function to limit how often a function can be called
|
|
2492
|
+
* @param {Function} func - Function to throttle
|
|
2493
|
+
* @param {number} limit - Time limit in milliseconds
|
|
2494
|
+
* @returns {Function} Throttled function
|
|
2495
|
+
*/
|
|
2496
|
+
function throttle(func, limit) {
|
|
2497
|
+
let inThrottle;
|
|
2498
|
+
return function() {
|
|
2499
|
+
const args = arguments;
|
|
2500
|
+
const context = this;
|
|
2501
|
+
if (!inThrottle) {
|
|
2502
|
+
func.apply(context, args);
|
|
2503
|
+
inThrottle = true;
|
|
2504
|
+
setTimeout(() => inThrottle = false, limit);
|
|
2505
|
+
}
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
/**
|
|
2510
|
+
* Request animation frame throttle for smooth animations
|
|
2511
|
+
* @param {Function} func - Function to throttle
|
|
2512
|
+
* @returns {Function} RAF throttled function
|
|
2513
|
+
*/
|
|
2514
|
+
function rafThrottle(func) {
|
|
2515
|
+
let isThrottled = false;
|
|
2516
|
+
return function() {
|
|
2517
|
+
if (isThrottled) return;
|
|
2518
|
+
|
|
2519
|
+
const args = arguments;
|
|
2520
|
+
const context = this;
|
|
2521
|
+
|
|
2522
|
+
isThrottled = true;
|
|
2523
|
+
requestAnimationFrame(() => {
|
|
2524
|
+
func.apply(context, args);
|
|
2525
|
+
isThrottled = false;
|
|
2526
|
+
});
|
|
2527
|
+
};
|
|
2528
|
+
}
|
|
2529
|
+
|
|
2530
|
+
/**
|
|
2531
|
+
* High performance transform utility
|
|
2532
|
+
* @param {HTMLElement} element - Element to transform
|
|
2533
|
+
* @param {number} x - X coordinate
|
|
2534
|
+
* @param {number} y - Y coordinate
|
|
2535
|
+
* @param {number} scale - Scale factor
|
|
2536
|
+
*/
|
|
2537
|
+
function setTransform(element, x, y, scale = 1) {
|
|
2538
|
+
// Use transform3d for hardware acceleration
|
|
2539
|
+
element.style.transform = `translate3d(${x}px, ${y}px, 0) scale(${scale})`;
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
/**
|
|
2543
|
+
* Reset element position efficiently
|
|
2544
|
+
* @param {HTMLElement} element - Element to reset
|
|
2545
|
+
*/
|
|
2546
|
+
function resetTransform(element) {
|
|
2547
|
+
element.style.transform = '';
|
|
2548
|
+
element.style.left = '';
|
|
2549
|
+
element.style.top = '';
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
/**
|
|
2553
|
+
* Cross-browser utilities for consistent drag & drop behavior
|
|
2554
|
+
*/
|
|
2555
|
+
|
|
2556
|
+
/**
|
|
2557
|
+
* Detect browser type and version
|
|
2558
|
+
* @returns {Object} Browser information
|
|
2559
|
+
*/
|
|
2560
|
+
function getBrowserInfo() {
|
|
2561
|
+
const ua = navigator.userAgent;
|
|
2562
|
+
const isChrome = ua.includes('Chrome') && !ua.includes('Edg');
|
|
2563
|
+
const isFirefox = ua.includes('Firefox');
|
|
2564
|
+
const isSafari = ua.includes('Safari') && !ua.includes('Chrome');
|
|
2565
|
+
const isEdge = ua.includes('Edg');
|
|
2566
|
+
|
|
2567
|
+
return {
|
|
2568
|
+
isChrome,
|
|
2569
|
+
isFirefox,
|
|
2570
|
+
isSafari,
|
|
2571
|
+
isEdge,
|
|
2572
|
+
devicePixelRatio: window.devicePixelRatio || 1,
|
|
2573
|
+
userAgent: ua
|
|
2574
|
+
};
|
|
2575
|
+
}
|
|
2576
|
+
|
|
2577
|
+
/**
|
|
2578
|
+
* Browser-specific drag optimizations
|
|
2579
|
+
*/
|
|
2580
|
+
const DragOptimizations = {
|
|
2581
|
+
/**
|
|
2582
|
+
* Apply browser-specific optimizations to an element
|
|
2583
|
+
* @param {HTMLElement} element - Element to optimize
|
|
2584
|
+
*/
|
|
2585
|
+
enableForDrag(element) {
|
|
2586
|
+
const browserInfo = getBrowserInfo();
|
|
2587
|
+
|
|
2588
|
+
// Base optimizations for all browsers
|
|
2589
|
+
element.style.willChange = 'left, top';
|
|
2590
|
+
element.style.pointerEvents = 'none'; // Prevent conflicts
|
|
2591
|
+
|
|
2592
|
+
// Chrome-specific optimizations
|
|
2593
|
+
if (browserInfo.isChrome) {
|
|
2594
|
+
element.style.transform = 'translateZ(0)'; // Force hardware acceleration
|
|
2595
|
+
}
|
|
2596
|
+
|
|
2597
|
+
// Firefox-specific optimizations
|
|
2598
|
+
if (browserInfo.isFirefox) {
|
|
2599
|
+
element.style.backfaceVisibility = 'hidden';
|
|
2600
|
+
}
|
|
2601
|
+
},
|
|
2602
|
+
|
|
2603
|
+
/**
|
|
2604
|
+
* Clean up optimizations after drag
|
|
2605
|
+
* @param {HTMLElement} element - Element to clean up
|
|
2606
|
+
*/
|
|
2607
|
+
cleanupAfterDrag(element) {
|
|
2608
|
+
element.style.willChange = 'auto';
|
|
2609
|
+
element.style.pointerEvents = '';
|
|
2610
|
+
element.style.transform = '';
|
|
2611
|
+
element.style.backfaceVisibility = '';
|
|
2612
|
+
}
|
|
2613
|
+
};
|
|
2614
|
+
|
|
2615
|
+
let Chessboard$1 = class Chessboard {
|
|
2448
2616
|
|
|
2449
2617
|
standard_positions = {
|
|
2450
2618
|
'start': 'start',
|
|
@@ -2491,7 +2659,10 @@ var Chessboard = (function () {
|
|
|
2491
2659
|
// Initialization
|
|
2492
2660
|
// -------------------
|
|
2493
2661
|
constructor(config) {
|
|
2662
|
+
// Debug: log the config to see what we're receiving
|
|
2663
|
+
console.log('Chessboard constructor received config:', config);
|
|
2494
2664
|
this.config = new ChessboardConfig(config);
|
|
2665
|
+
console.log('Processed config.id_div:', this.config.id_div);
|
|
2495
2666
|
this.init();
|
|
2496
2667
|
}
|
|
2497
2668
|
|
|
@@ -2511,12 +2682,17 @@ var Chessboard = (function () {
|
|
|
2511
2682
|
this.clicked = null;
|
|
2512
2683
|
this.mosseIndietro = [];
|
|
2513
2684
|
this.clicked = null;
|
|
2685
|
+
this._updateTimeout = null; // For debouncing board updates
|
|
2686
|
+
this._movesCache = new Map(); // Cache per le mosse per migliorare le prestazioni
|
|
2687
|
+
this._cacheTimeout = null; // Timeout per pulire la cache
|
|
2688
|
+
this._isAnimating = false; // Flag to track if animations are in progress
|
|
2514
2689
|
}
|
|
2515
2690
|
|
|
2516
2691
|
// -------------------
|
|
2517
2692
|
// Board Setup
|
|
2518
2693
|
// -------------------
|
|
2519
2694
|
buildBoard() {
|
|
2695
|
+
console.log('buildBoard: Looking for element with ID:', this.config.id_div, 'Type:', typeof this.config.id_div);
|
|
2520
2696
|
this.element = document.getElementById(this.config.id_div);
|
|
2521
2697
|
if (!this.element) {
|
|
2522
2698
|
throw new Error(this.error_messages['invalid_id_div'] + this.config.id_div);
|
|
@@ -2672,17 +2848,38 @@ var Chessboard = (function () {
|
|
|
2672
2848
|
}
|
|
2673
2849
|
|
|
2674
2850
|
movePiece(piece, to, duration, callback) {
|
|
2851
|
+
if (!piece) {
|
|
2852
|
+
console.warn('movePiece: piece is null, skipping animation');
|
|
2853
|
+
if (callback) callback();
|
|
2854
|
+
return;
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2675
2857
|
piece.translate(to, duration, this.transitionTimingFunction, this.config.moveAnimation, callback);
|
|
2676
2858
|
}
|
|
2677
2859
|
|
|
2678
2860
|
translatePiece(move, removeTo, animate, callback = null) {
|
|
2861
|
+
if (!move.piece) {
|
|
2862
|
+
console.warn('translatePiece: move.piece is null, skipping translation');
|
|
2863
|
+
if (callback) callback();
|
|
2864
|
+
return;
|
|
2865
|
+
}
|
|
2679
2866
|
|
|
2680
|
-
if (removeTo)
|
|
2867
|
+
if (removeTo) {
|
|
2868
|
+
// Deselect the captured piece before removing it
|
|
2869
|
+
move.to.deselect();
|
|
2870
|
+
this.removePieceFromSquare(move.to, false);
|
|
2871
|
+
}
|
|
2681
2872
|
|
|
2682
2873
|
let change_square = () => {
|
|
2683
|
-
|
|
2684
|
-
move.
|
|
2685
|
-
|
|
2874
|
+
// Check if piece still exists and is on the source square
|
|
2875
|
+
if (move.from.piece === move.piece) {
|
|
2876
|
+
move.from.removePiece();
|
|
2877
|
+
}
|
|
2878
|
+
// Only put piece if destination square doesn't already have it
|
|
2879
|
+
if (move.to.piece !== move.piece) {
|
|
2880
|
+
move.to.putPiece(move.piece);
|
|
2881
|
+
move.piece.setDrag(this.dragFunction(move.to, move.piece));
|
|
2882
|
+
}
|
|
2686
2883
|
if (callback) callback();
|
|
2687
2884
|
};
|
|
2688
2885
|
|
|
@@ -2693,14 +2890,49 @@ var Chessboard = (function () {
|
|
|
2693
2890
|
}
|
|
2694
2891
|
|
|
2695
2892
|
snapbackPiece(square, animate = this.config.snapbackAnimation) {
|
|
2696
|
-
|
|
2697
|
-
|
|
2893
|
+
if (!square || !square.piece) {
|
|
2894
|
+
return;
|
|
2895
|
+
}
|
|
2896
|
+
|
|
2897
|
+
const piece = square.piece;
|
|
2898
|
+
|
|
2899
|
+
// Use the piece's translate method to properly animate back to the square
|
|
2900
|
+
const duration = animate ? this.config.snapbackTime : 0;
|
|
2901
|
+
|
|
2902
|
+
// The translate method will calculate the proper distance from current visual position
|
|
2903
|
+
// back to the square's position
|
|
2904
|
+
piece.translate(square, duration, this.transitionTimingFunction, animate);
|
|
2698
2905
|
}
|
|
2699
2906
|
|
|
2700
2907
|
// -------------------
|
|
2701
2908
|
// Board Update Functions
|
|
2702
2909
|
// -------------------
|
|
2703
2910
|
updateBoardPieces(animation = false) {
|
|
2911
|
+
// Clear any pending update to avoid duplicate calls
|
|
2912
|
+
if (this._updateTimeout) {
|
|
2913
|
+
clearTimeout(this._updateTimeout);
|
|
2914
|
+
this._updateTimeout = null;
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
// Pulisce la cache delle mosse quando la posizione cambia
|
|
2918
|
+
this._movesCache.clear();
|
|
2919
|
+
if (this._cacheTimeout) {
|
|
2920
|
+
clearTimeout(this._cacheTimeout);
|
|
2921
|
+
this._cacheTimeout = null;
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
// For click-to-move, add a small delay to avoid lag
|
|
2925
|
+
if (animation && this.clicked === null) {
|
|
2926
|
+
this._updateTimeout = setTimeout(() => {
|
|
2927
|
+
this._doUpdateBoardPieces(animation);
|
|
2928
|
+
this._updateTimeout = null;
|
|
2929
|
+
}, 10);
|
|
2930
|
+
} else {
|
|
2931
|
+
this._doUpdateBoardPieces(animation);
|
|
2932
|
+
}
|
|
2933
|
+
}
|
|
2934
|
+
|
|
2935
|
+
_doUpdateBoardPieces(animation = false) {
|
|
2704
2936
|
let { updatedFlags, escapeFlags, movableFlags, pendingTranslations } = this.prepareBoardUpdateData();
|
|
2705
2937
|
|
|
2706
2938
|
let change = Object.values(updatedFlags).some(flag => !flag);
|
|
@@ -2840,30 +3072,91 @@ var Chessboard = (function () {
|
|
|
2840
3072
|
|
|
2841
3073
|
if (!this.config.draggable || !piece) return;
|
|
2842
3074
|
|
|
3075
|
+
// Store the original from square for the entire drag operation
|
|
3076
|
+
const originalFrom = square;
|
|
2843
3077
|
let prec;
|
|
2844
|
-
let from =
|
|
3078
|
+
let from = originalFrom;
|
|
2845
3079
|
let to = square;
|
|
2846
3080
|
|
|
2847
3081
|
const img = piece.element;
|
|
2848
3082
|
|
|
2849
3083
|
if (!this.canMove(from)) return;
|
|
2850
|
-
|
|
2851
|
-
if
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
3084
|
+
|
|
3085
|
+
// Track if this is actually a drag operation or just a click
|
|
3086
|
+
let isDragging = false;
|
|
3087
|
+
let startX = event.clientX || (event.touches && event.touches[0] ? event.touches[0].clientX : 0);
|
|
3088
|
+
let startY = event.clientY || (event.touches && event.touches[0] ? event.touches[0].clientY : 0);
|
|
3089
|
+
|
|
3090
|
+
// Don't interfere with click system immediately
|
|
3091
|
+
console.log('dragFunction: mousedown detected, waiting to see if it becomes drag');
|
|
3092
|
+
|
|
3093
|
+
const moveAt = (event) => {
|
|
3094
|
+
const squareSize = this.element.offsetWidth / 8;
|
|
3095
|
+
|
|
3096
|
+
// Get mouse coordinates - use clientX/Y for better Chrome compatibility
|
|
3097
|
+
let clientX, clientY;
|
|
3098
|
+
if (event.touches && event.touches[0]) {
|
|
3099
|
+
clientX = event.touches[0].clientX;
|
|
3100
|
+
clientY = event.touches[0].clientY;
|
|
3101
|
+
} else {
|
|
3102
|
+
clientX = event.clientX;
|
|
3103
|
+
clientY = event.clientY;
|
|
3104
|
+
}
|
|
3105
|
+
|
|
3106
|
+
// Get board position using getBoundingClientRect for accuracy
|
|
3107
|
+
const boardRect = this.element.getBoundingClientRect();
|
|
3108
|
+
|
|
3109
|
+
// Calculate position relative to board with piece centered on cursor
|
|
3110
|
+
// Add window scroll offset for correct positioning
|
|
3111
|
+
window.pageXOffset || document.documentElement.scrollLeft;
|
|
3112
|
+
window.pageYOffset || document.documentElement.scrollTop;
|
|
3113
|
+
|
|
3114
|
+
const x = clientX - boardRect.left - (squareSize / 2);
|
|
3115
|
+
const y = clientY - boardRect.top - (squareSize / 2);
|
|
3116
|
+
|
|
3117
|
+
img.style.left = x + 'px';
|
|
3118
|
+
img.style.top = y + 'px';
|
|
2861
3119
|
return true;
|
|
2862
3120
|
};
|
|
2863
3121
|
|
|
2864
3122
|
const onMouseMove = (event) => {
|
|
3123
|
+
// Check if mouse has moved enough to be considered a drag
|
|
3124
|
+
let currentX = event.clientX;
|
|
3125
|
+
let currentY = event.clientY;
|
|
3126
|
+
let deltaX = Math.abs(currentX - startX);
|
|
3127
|
+
let deltaY = Math.abs(currentY - startY);
|
|
3128
|
+
|
|
3129
|
+
// Only start dragging if mouse moved more than 3 pixels
|
|
3130
|
+
if (!isDragging && (deltaX > 3 || deltaY > 3)) {
|
|
3131
|
+
console.log('dragFunction: starting actual drag operation');
|
|
3132
|
+
isDragging = true;
|
|
3133
|
+
|
|
3134
|
+
// Now set up drag state
|
|
3135
|
+
if (!this.config.clickable) {
|
|
3136
|
+
this.clicked = null;
|
|
3137
|
+
this.clicked = from;
|
|
3138
|
+
} else if (!this.clicked) {
|
|
3139
|
+
this.clicked = from;
|
|
3140
|
+
}
|
|
3141
|
+
console.log('dragFunction: clicked state after drag activation =', this.clicked ? this.clicked.id : 'none');
|
|
3142
|
+
|
|
3143
|
+
// Highlight the source square and show hints
|
|
3144
|
+
if (this.config.clickable) {
|
|
3145
|
+
from.select();
|
|
3146
|
+
this.hintMoves(from);
|
|
3147
|
+
}
|
|
3148
|
+
|
|
3149
|
+
img.style.position = 'absolute';
|
|
3150
|
+
img.style.zIndex = 100;
|
|
3151
|
+
img.classList.add('dragging');
|
|
3152
|
+
|
|
3153
|
+
DragOptimizations.enableForDrag(img);
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
if (!isDragging) return;
|
|
3157
|
+
|
|
2865
3158
|
if (!this.config.onDragStart(square, piece)) return;
|
|
2866
|
-
if (!moveAt(event
|
|
3159
|
+
if (!moveAt(event)) ;
|
|
2867
3160
|
|
|
2868
3161
|
const boardRect = this.element.getBoundingClientRect();
|
|
2869
3162
|
const { offsetWidth: boardWidth, offsetHeight: boardHeight } = this.element;
|
|
@@ -2891,19 +3184,44 @@ var Chessboard = (function () {
|
|
|
2891
3184
|
prec?.dehighlight();
|
|
2892
3185
|
document.removeEventListener('mousemove', onMouseMove);
|
|
2893
3186
|
window.removeEventListener('mouseup', onMouseUp);
|
|
3187
|
+
|
|
3188
|
+
// If this was just a click (not a drag), don't interfere
|
|
3189
|
+
if (!isDragging) {
|
|
3190
|
+
console.log('dragFunction: was just a click, not interfering');
|
|
3191
|
+
return;
|
|
3192
|
+
}
|
|
3193
|
+
|
|
3194
|
+
console.log('dragFunction: ending drag operation');
|
|
2894
3195
|
img.style.zIndex = 20;
|
|
3196
|
+
img.classList.remove('dragging');
|
|
3197
|
+
img.style.willChange = 'auto';
|
|
2895
3198
|
|
|
2896
|
-
const dropResult = this.config.onDrop(
|
|
3199
|
+
const dropResult = this.config.onDrop(originalFrom, to, piece);
|
|
2897
3200
|
const isTrashDrop = !to && (this.config.dropOffBoard === 'trash' || dropResult === 'trash');
|
|
2898
3201
|
|
|
2899
3202
|
if (isTrashDrop) {
|
|
2900
3203
|
this.allSquares("unmoved");
|
|
2901
3204
|
this.allSquares('removeHint');
|
|
2902
|
-
|
|
2903
|
-
this.remove(
|
|
2904
|
-
} else if (!to
|
|
2905
|
-
|
|
2906
|
-
if (
|
|
3205
|
+
originalFrom.deselect();
|
|
3206
|
+
this.remove(originalFrom);
|
|
3207
|
+
} else if (!to) {
|
|
3208
|
+
// No target square - snapback
|
|
3209
|
+
if (originalFrom && originalFrom.piece) {
|
|
3210
|
+
this.snapbackPiece(originalFrom);
|
|
3211
|
+
if (to !== originalFrom) this.config.onSnapbackEnd(originalFrom, piece);
|
|
3212
|
+
}
|
|
3213
|
+
} else {
|
|
3214
|
+
// Set clicked to originalFrom before attempting move
|
|
3215
|
+
this.clicked = originalFrom;
|
|
3216
|
+
// Try to make the move
|
|
3217
|
+
const onClickResult = this.onClick(to, true, true);
|
|
3218
|
+
if (!onClickResult) {
|
|
3219
|
+
// Move failed - snapback
|
|
3220
|
+
if (originalFrom && originalFrom.piece) {
|
|
3221
|
+
this.snapbackPiece(originalFrom);
|
|
3222
|
+
if (to !== originalFrom) this.config.onSnapbackEnd(originalFrom, piece);
|
|
3223
|
+
}
|
|
3224
|
+
}
|
|
2907
3225
|
}
|
|
2908
3226
|
};
|
|
2909
3227
|
|
|
@@ -2916,32 +3234,38 @@ var Chessboard = (function () {
|
|
|
2916
3234
|
addListeners() {
|
|
2917
3235
|
for (const square of Object.values(this.squares)) {
|
|
2918
3236
|
|
|
2919
|
-
|
|
3237
|
+
square.piece;
|
|
2920
3238
|
|
|
2921
|
-
|
|
2922
|
-
|
|
3239
|
+
// Applica throttling ai listener di mouseover e mouseout per migliori prestazioni
|
|
3240
|
+
const throttledHintMoves = rafThrottle((e) => {
|
|
3241
|
+
if (!this.clicked && this.config.hints) this.hintMoves(square);
|
|
2923
3242
|
});
|
|
2924
|
-
|
|
2925
|
-
|
|
3243
|
+
|
|
3244
|
+
const throttledDehintMoves = rafThrottle((e) => {
|
|
3245
|
+
if (!this.clicked && this.config.hints) this.dehintMoves(square);
|
|
2926
3246
|
});
|
|
2927
3247
|
|
|
3248
|
+
square.element.addEventListener("mouseover", throttledHintMoves);
|
|
3249
|
+
square.element.addEventListener("mouseout", throttledDehintMoves);
|
|
3250
|
+
|
|
2928
3251
|
const handleClick = (e) => {
|
|
2929
3252
|
e.stopPropagation();
|
|
2930
|
-
if (this.config.clickable
|
|
3253
|
+
if (this.config.clickable) {
|
|
3254
|
+
this.onClick(square);
|
|
3255
|
+
}
|
|
2931
3256
|
};
|
|
2932
3257
|
|
|
2933
|
-
square.element.addEventListener("
|
|
3258
|
+
square.element.addEventListener("click", handleClick);
|
|
2934
3259
|
square.element.addEventListener("touch", handleClick);
|
|
2935
3260
|
}
|
|
2936
3261
|
}
|
|
2937
3262
|
|
|
2938
3263
|
onClick(square, animation = this.config.moveAnimation, dragged = false) {
|
|
2939
3264
|
|
|
2940
|
-
|
|
2941
|
-
|
|
3265
|
+
console.log('onClick START: square =', square.id, 'clicked =', this.clicked ? this.clicked.id : 'none');
|
|
3266
|
+
|
|
2942
3267
|
let from = this.clicked;
|
|
2943
|
-
|
|
2944
|
-
|
|
3268
|
+
|
|
2945
3269
|
let promotion = null;
|
|
2946
3270
|
|
|
2947
3271
|
if (this.promoting) {
|
|
@@ -2953,36 +3277,75 @@ var Chessboard = (function () {
|
|
|
2953
3277
|
this.allSquares("removeCover");
|
|
2954
3278
|
}
|
|
2955
3279
|
|
|
2956
|
-
|
|
3280
|
+
console.log('onClick: from =', from ? from.id : 'none');
|
|
2957
3281
|
|
|
3282
|
+
if (!from) {
|
|
3283
|
+
console.log('onClick: no from, trying to select piece');
|
|
2958
3284
|
if (this.canMove(square)) {
|
|
3285
|
+
console.log('onClick: canMove = true, selecting');
|
|
2959
3286
|
if (this.config.clickable) {
|
|
2960
3287
|
square.select();
|
|
2961
3288
|
this.hintMoves(square);
|
|
2962
3289
|
}
|
|
2963
3290
|
this.clicked = square;
|
|
3291
|
+
console.log('onClick: *** CLICKED SET TO ***', square.id);
|
|
3292
|
+
console.log('onClick: set clicked to', square.id);
|
|
3293
|
+
} else {
|
|
3294
|
+
console.log('onClick: canMove = false');
|
|
2964
3295
|
}
|
|
3296
|
+
return false;
|
|
3297
|
+
}
|
|
2965
3298
|
|
|
3299
|
+
// If clicking on the same square that's already selected, deselect it
|
|
3300
|
+
if (this.clicked === square) {
|
|
3301
|
+
console.log('onClick: deselecting same square');
|
|
3302
|
+
square.deselect();
|
|
3303
|
+
this.allSquares("removeHint");
|
|
3304
|
+
this.clicked = null;
|
|
3305
|
+
console.log('onClick: *** CLICKED RESET TO NULL (deselect) ***');
|
|
2966
3306
|
return false;
|
|
2967
3307
|
}
|
|
2968
3308
|
|
|
3309
|
+
console.log('onClick: attempting move from', from.id, 'to', square.id);
|
|
2969
3310
|
let move = new Move(from, square, promotion);
|
|
2970
3311
|
|
|
2971
|
-
move.
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
3312
|
+
if (!move.check()) {
|
|
3313
|
+
console.log('onClick: move check FAILED');
|
|
3314
|
+
from.deselect();
|
|
3315
|
+
this.allSquares("removeHint");
|
|
3316
|
+
this.clicked = null;
|
|
3317
|
+
return false;
|
|
3318
|
+
}
|
|
2976
3319
|
|
|
2977
|
-
if (this.config.onlyLegalMoves && !move.isLegal(this.game))
|
|
3320
|
+
if (this.config.onlyLegalMoves && !move.isLegal(this.game)) {
|
|
3321
|
+
console.log('onClick: move is NOT LEGAL');
|
|
3322
|
+
from.deselect();
|
|
3323
|
+
this.allSquares("removeHint");
|
|
3324
|
+
this.clicked = null;
|
|
3325
|
+
return false;
|
|
3326
|
+
}
|
|
2978
3327
|
|
|
2979
|
-
if (!move.hasPromotion() && this.promote(move))
|
|
3328
|
+
if (!move.hasPromotion() && this.promote(move)) {
|
|
3329
|
+
console.log('onClick: promotion required');
|
|
3330
|
+
return false;
|
|
3331
|
+
}
|
|
2980
3332
|
|
|
3333
|
+
console.log('onClick: calling onMove');
|
|
2981
3334
|
if (this.config.onMove(move)) {
|
|
3335
|
+
console.log('onClick: SUCCESS - move executed');
|
|
3336
|
+
// Clean up UI state
|
|
3337
|
+
from.deselect();
|
|
3338
|
+
this.allSquares("removeHint");
|
|
3339
|
+
this.clicked = null;
|
|
3340
|
+
console.log('onClick: *** CLICKED RESET TO NULL (success) ***');
|
|
2982
3341
|
this.move(move, animation);
|
|
2983
3342
|
return true;
|
|
2984
3343
|
}
|
|
2985
3344
|
|
|
3345
|
+
console.log('onClick: onMove returned FALSE');
|
|
3346
|
+
from.deselect();
|
|
3347
|
+
this.allSquares("removeHint");
|
|
3348
|
+
this.clicked = null;
|
|
2986
3349
|
return false;
|
|
2987
3350
|
}
|
|
2988
3351
|
|
|
@@ -3033,12 +3396,14 @@ var Chessboard = (function () {
|
|
|
3033
3396
|
let from = move.from;
|
|
3034
3397
|
let to = move.to;
|
|
3035
3398
|
|
|
3399
|
+
// Store the current state to avoid unnecessary recalculations
|
|
3400
|
+
const gameStateBefore = this.game.fen();
|
|
3401
|
+
|
|
3036
3402
|
if (!this.config.onlyLegalMoves) {
|
|
3037
3403
|
let piece = this.getGamePieceId(from.id);
|
|
3038
3404
|
this.game.remove(from.id);
|
|
3039
3405
|
this.game.remove(to.id);
|
|
3040
3406
|
this.game.put({ type: move.hasPromotion() ? move.promotion : piece[0], color: piece[1] }, to.id);
|
|
3041
|
-
this.updateBoardPieces(animation);
|
|
3042
3407
|
} else {
|
|
3043
3408
|
this.allSquares("unmoved");
|
|
3044
3409
|
|
|
@@ -3052,12 +3417,18 @@ var Chessboard = (function () {
|
|
|
3052
3417
|
throw new Error("Invalid move: move could not be executed");
|
|
3053
3418
|
}
|
|
3054
3419
|
|
|
3055
|
-
this.updateBoardPieces(animation);
|
|
3056
|
-
|
|
3057
3420
|
from.moved();
|
|
3058
3421
|
to.moved();
|
|
3059
3422
|
this.allSquares("removeHint");
|
|
3423
|
+
}
|
|
3060
3424
|
|
|
3425
|
+
// Only update the board if the game state actually changed
|
|
3426
|
+
const gameStateAfter = this.game.fen();
|
|
3427
|
+
if (gameStateBefore !== gameStateAfter) {
|
|
3428
|
+
this.updateBoardPieces(animation);
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3431
|
+
if (this.config.onlyLegalMoves) {
|
|
3061
3432
|
this.config.onMoveEnd(move);
|
|
3062
3433
|
}
|
|
3063
3434
|
}
|
|
@@ -3073,14 +3444,37 @@ var Chessboard = (function () {
|
|
|
3073
3444
|
|
|
3074
3445
|
hintMoves(square) {
|
|
3075
3446
|
if (!this.canMove(square)) return;
|
|
3076
|
-
|
|
3447
|
+
|
|
3448
|
+
// Usa la cache per evitare calcoli ripetuti delle mosse
|
|
3449
|
+
const cacheKey = `${square.id}-${this.game.fen()}`;
|
|
3450
|
+
let mosse = this._movesCache.get(cacheKey);
|
|
3451
|
+
|
|
3452
|
+
if (!mosse) {
|
|
3453
|
+
mosse = this.game.moves({ square: square.id, verbose: true });
|
|
3454
|
+
this._movesCache.set(cacheKey, mosse);
|
|
3455
|
+
|
|
3456
|
+
// Pulisci la cache dopo un breve ritardo per evitare accumulo di memoria
|
|
3457
|
+
if (this._cacheTimeout) clearTimeout(this._cacheTimeout);
|
|
3458
|
+
this._cacheTimeout = setTimeout(() => {
|
|
3459
|
+
this._movesCache.clear();
|
|
3460
|
+
}, 1000);
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3077
3463
|
for (let mossa of mosse) {
|
|
3078
3464
|
if (mossa['to'].length === 2) this.hint(mossa['to']);
|
|
3079
3465
|
}
|
|
3080
3466
|
}
|
|
3081
3467
|
|
|
3082
3468
|
dehintMoves(square) {
|
|
3083
|
-
|
|
3469
|
+
// Usa la cache anche per dehint per coerenza
|
|
3470
|
+
const cacheKey = `${square.id}-${this.game.fen()}`;
|
|
3471
|
+
let mosse = this._movesCache.get(cacheKey);
|
|
3472
|
+
|
|
3473
|
+
if (!mosse) {
|
|
3474
|
+
mosse = this.game.moves({ square: square.id, verbose: true });
|
|
3475
|
+
this._movesCache.set(cacheKey, mosse);
|
|
3476
|
+
}
|
|
3477
|
+
|
|
3084
3478
|
for (let mossa of mosse) {
|
|
3085
3479
|
let to = this.squares[mossa['to']];
|
|
3086
3480
|
to.removeHint();
|
|
@@ -3413,10 +3807,266 @@ var Chessboard = (function () {
|
|
|
3413
3807
|
|
|
3414
3808
|
isWhiteOriented() { return this.config.orientation === 'w' }
|
|
3415
3809
|
|
|
3810
|
+
};
|
|
3811
|
+
|
|
3812
|
+
/**
|
|
3813
|
+
* Chessboard.js - A beautiful, customizable chessboard widget
|
|
3814
|
+
* Entry point for the core library
|
|
3815
|
+
*/
|
|
3816
|
+
|
|
3817
|
+
|
|
3818
|
+
// Factory function to maintain backward compatibility
|
|
3819
|
+
function Chessboard(containerElm, config = {}) {
|
|
3820
|
+
// If first parameter is an object, treat it as config
|
|
3821
|
+
if (typeof containerElm === 'object' && containerElm !== null) {
|
|
3822
|
+
return new Chessboard$1(containerElm);
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
// Otherwise, treat first parameter as element ID
|
|
3826
|
+
const fullConfig = { ...config, id: containerElm };
|
|
3827
|
+
return new Chessboard$1(fullConfig);
|
|
3828
|
+
}
|
|
3829
|
+
|
|
3830
|
+
// Wrapper class that handles both calling conventions
|
|
3831
|
+
class ChessboardWrapper extends Chessboard$1 {
|
|
3832
|
+
constructor(containerElm, config = {}) {
|
|
3833
|
+
// If first parameter is an object, treat it as config
|
|
3834
|
+
if (typeof containerElm === 'object' && containerElm !== null) {
|
|
3835
|
+
super(containerElm);
|
|
3836
|
+
} else {
|
|
3837
|
+
// Otherwise, treat first parameter as element ID
|
|
3838
|
+
const fullConfig = { ...config, id: containerElm };
|
|
3839
|
+
super(fullConfig);
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
}
|
|
3843
|
+
|
|
3844
|
+
// Attach the class to the factory function for direct access
|
|
3845
|
+
Chessboard.Class = ChessboardWrapper;
|
|
3846
|
+
Chessboard.Chessboard = ChessboardWrapper;
|
|
3847
|
+
|
|
3848
|
+
/**
|
|
3849
|
+
* Coordinate utilities for Chessboard.js
|
|
3850
|
+
*/
|
|
3851
|
+
|
|
3852
|
+
/**
|
|
3853
|
+
* Convert algebraic notation to array coordinates
|
|
3854
|
+
* @param {string} square - Square in algebraic notation (e.g., 'a1', 'h8')
|
|
3855
|
+
* @returns {Object} Object with row and col properties
|
|
3856
|
+
*/
|
|
3857
|
+
function algebraicToCoords(square) {
|
|
3858
|
+
const file = square.charCodeAt(0) - 97; // 'a' = 0, 'b' = 1, etc.
|
|
3859
|
+
const rank = parseInt(square[1]) - 1; // '1' = 0, '2' = 1, etc.
|
|
3860
|
+
|
|
3861
|
+
return { row: 7 - rank, col: file };
|
|
3862
|
+
}
|
|
3863
|
+
|
|
3864
|
+
/**
|
|
3865
|
+
* Convert array coordinates to algebraic notation
|
|
3866
|
+
* @param {number} row - Row index (0-7)
|
|
3867
|
+
* @param {number} col - Column index (0-7)
|
|
3868
|
+
* @returns {string} Square in algebraic notation
|
|
3869
|
+
*/
|
|
3870
|
+
function coordsToAlgebraic(row, col) {
|
|
3871
|
+
const file = String.fromCharCode(97 + col); // 0 = 'a', 1 = 'b', etc.
|
|
3872
|
+
const rank = (8 - row).toString(); // 0 = '8', 1 = '7', etc.
|
|
3873
|
+
|
|
3874
|
+
return file + rank;
|
|
3875
|
+
}
|
|
3876
|
+
|
|
3877
|
+
/**
|
|
3878
|
+
* Get the color of a square
|
|
3879
|
+
* @param {string} square - Square in algebraic notation
|
|
3880
|
+
* @returns {string} 'light' or 'dark'
|
|
3881
|
+
*/
|
|
3882
|
+
function getSquareColor(square) {
|
|
3883
|
+
const { row, col } = algebraicToCoords(square);
|
|
3884
|
+
return (row + col) % 2 === 0 ? 'dark' : 'light';
|
|
3885
|
+
}
|
|
3886
|
+
|
|
3887
|
+
/**
|
|
3888
|
+
* Check if coordinates are valid
|
|
3889
|
+
* @param {number} row - Row index
|
|
3890
|
+
* @param {number} col - Column index
|
|
3891
|
+
* @returns {boolean} True if coordinates are valid
|
|
3892
|
+
*/
|
|
3893
|
+
function isValidCoords(row, col) {
|
|
3894
|
+
return row >= 0 && row <= 7 && col >= 0 && col <= 7;
|
|
3895
|
+
}
|
|
3896
|
+
|
|
3897
|
+
/**
|
|
3898
|
+
* Check if algebraic notation is valid
|
|
3899
|
+
* @param {string} square - Square in algebraic notation
|
|
3900
|
+
* @returns {boolean} True if square notation is valid
|
|
3901
|
+
*/
|
|
3902
|
+
function isValidSquare$1(square) {
|
|
3903
|
+
if (typeof square !== 'string' || square.length !== 2) return false;
|
|
3904
|
+
|
|
3905
|
+
const file = square[0];
|
|
3906
|
+
const rank = square[1];
|
|
3907
|
+
|
|
3908
|
+
return file >= 'a' && file <= 'h' && rank >= '1' && rank <= '8';
|
|
3909
|
+
}
|
|
3910
|
+
|
|
3911
|
+
/**
|
|
3912
|
+
* Validation utilities for Chessboard.js
|
|
3913
|
+
*/
|
|
3914
|
+
|
|
3915
|
+
/**
|
|
3916
|
+
* Validate piece notation
|
|
3917
|
+
* @param {string} piece - Piece notation (e.g., 'wP', 'bK')
|
|
3918
|
+
* @returns {boolean} True if piece notation is valid
|
|
3919
|
+
*/
|
|
3920
|
+
function isValidPiece(piece) {
|
|
3921
|
+
if (typeof piece !== 'string' || piece.length !== 2) return false;
|
|
3922
|
+
|
|
3923
|
+
const color = piece[0];
|
|
3924
|
+
const type = piece[1];
|
|
3925
|
+
|
|
3926
|
+
return ['w', 'b'].includes(color) && ['P', 'R', 'N', 'B', 'Q', 'K'].includes(type);
|
|
3927
|
+
}
|
|
3928
|
+
|
|
3929
|
+
/**
|
|
3930
|
+
* Validate position object
|
|
3931
|
+
* @param {Object} position - Position object with square-piece mappings
|
|
3932
|
+
* @returns {boolean} True if position is valid
|
|
3933
|
+
*/
|
|
3934
|
+
function isValidPosition(position) {
|
|
3935
|
+
if (typeof position !== 'object' || position === null) return false;
|
|
3936
|
+
|
|
3937
|
+
for (const [square, piece] of Object.entries(position)) {
|
|
3938
|
+
if (!isValidSquare(square) || !isValidPiece(piece)) {
|
|
3939
|
+
return false;
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
|
|
3943
|
+
return true;
|
|
3944
|
+
}
|
|
3945
|
+
|
|
3946
|
+
/**
|
|
3947
|
+
* Validate FEN string format
|
|
3948
|
+
* @param {string} fen - FEN string
|
|
3949
|
+
* @returns {Object} Validation result with success and error properties
|
|
3950
|
+
*/
|
|
3951
|
+
function validateFenFormat(fen) {
|
|
3952
|
+
if (typeof fen !== 'string') {
|
|
3953
|
+
return { success: false, error: 'FEN must be a string' };
|
|
3954
|
+
}
|
|
3955
|
+
|
|
3956
|
+
const parts = fen.split(' ');
|
|
3957
|
+
if (parts.length !== 6) {
|
|
3958
|
+
return { success: false, error: 'FEN must have 6 parts separated by spaces' };
|
|
3959
|
+
}
|
|
3960
|
+
|
|
3961
|
+
// Validate piece placement
|
|
3962
|
+
const ranks = parts[0].split('/');
|
|
3963
|
+
if (ranks.length !== 8) {
|
|
3964
|
+
return { success: false, error: 'Piece placement must have 8 ranks' };
|
|
3965
|
+
}
|
|
3966
|
+
|
|
3967
|
+
return { success: true };
|
|
3968
|
+
}
|
|
3969
|
+
|
|
3970
|
+
/**
|
|
3971
|
+
* Validate configuration object
|
|
3972
|
+
* @param {Object} config - Configuration object
|
|
3973
|
+
* @returns {Object} Validation result with success and errors array
|
|
3974
|
+
*/
|
|
3975
|
+
function validateConfig(config) {
|
|
3976
|
+
const errors = [];
|
|
3977
|
+
|
|
3978
|
+
if (config.orientation && !['white', 'black', 'w', 'b'].includes(config.orientation)) {
|
|
3979
|
+
errors.push('Invalid orientation. Must be "white", "black", "w", or "b"');
|
|
3980
|
+
}
|
|
3981
|
+
|
|
3982
|
+
if (config.position && config.position !== 'start' && typeof config.position !== 'object') {
|
|
3983
|
+
errors.push('Invalid position. Must be "start" or a position object');
|
|
3984
|
+
}
|
|
3985
|
+
|
|
3986
|
+
if (config.size && typeof config.size !== 'string' && typeof config.size !== 'number') {
|
|
3987
|
+
errors.push('Invalid size. Must be a string or number');
|
|
3988
|
+
}
|
|
3989
|
+
|
|
3990
|
+
return {
|
|
3991
|
+
success: errors.length === 0,
|
|
3992
|
+
errors
|
|
3993
|
+
};
|
|
3416
3994
|
}
|
|
3417
3995
|
|
|
3418
|
-
|
|
3996
|
+
/**
|
|
3997
|
+
* Animation utilities for Chessboard.js
|
|
3998
|
+
*/
|
|
3419
3999
|
|
|
3420
|
-
|
|
4000
|
+
/**
|
|
4001
|
+
* Get the CSS transition duration in milliseconds
|
|
4002
|
+
* @param {string|number} time - Time value ('fast', 'slow', or number in ms)
|
|
4003
|
+
* @returns {number} Duration in milliseconds
|
|
4004
|
+
*/
|
|
4005
|
+
function parseTime(time) {
|
|
4006
|
+
if (typeof time === 'number') return time;
|
|
4007
|
+
|
|
4008
|
+
switch (time) {
|
|
4009
|
+
case 'fast': return 150;
|
|
4010
|
+
case 'slow': return 500;
|
|
4011
|
+
default: return 200;
|
|
4012
|
+
}
|
|
4013
|
+
}
|
|
4014
|
+
|
|
4015
|
+
/**
|
|
4016
|
+
* Get the CSS transition function
|
|
4017
|
+
* @param {string} animation - Animation type ('ease', 'linear', etc.)
|
|
4018
|
+
* @returns {string} CSS transition function
|
|
4019
|
+
*/
|
|
4020
|
+
function parseAnimation(animation) {
|
|
4021
|
+
const validAnimations = ['ease', 'ease-in', 'ease-out', 'ease-in-out', 'linear'];
|
|
4022
|
+
return validAnimations.includes(animation) ? animation : 'ease';
|
|
4023
|
+
}
|
|
4024
|
+
|
|
4025
|
+
/**
|
|
4026
|
+
* Create a promise that resolves after animation completion
|
|
4027
|
+
* @param {number} duration - Duration in milliseconds
|
|
4028
|
+
* @returns {Promise} Promise that resolves after the duration
|
|
4029
|
+
*/
|
|
4030
|
+
function animationPromise(duration) {
|
|
4031
|
+
return new Promise(resolve => setTimeout(resolve, duration));
|
|
4032
|
+
}
|
|
4033
|
+
|
|
4034
|
+
/**
|
|
4035
|
+
* Chessboard.js - A beautiful, customizable chessboard widget
|
|
4036
|
+
* Main entry point for the library
|
|
4037
|
+
*
|
|
4038
|
+
* @version 2.2.1
|
|
4039
|
+
* @author alepot55
|
|
4040
|
+
* @license ISC
|
|
4041
|
+
*/
|
|
3421
4042
|
|
|
3422
|
-
|
|
4043
|
+
exports.Chess = Chess;
|
|
4044
|
+
exports.Chessboard = Chessboard;
|
|
4045
|
+
exports.ChessboardConfig = ChessboardConfig;
|
|
4046
|
+
exports.Move = Move;
|
|
4047
|
+
exports.Piece = Piece;
|
|
4048
|
+
exports.Square = Square;
|
|
4049
|
+
exports.algebraicToCoords = algebraicToCoords;
|
|
4050
|
+
exports.animationPromise = animationPromise;
|
|
4051
|
+
exports.coordsToAlgebraic = coordsToAlgebraic;
|
|
4052
|
+
exports.default = Chessboard;
|
|
4053
|
+
exports.getSquareColor = getSquareColor;
|
|
4054
|
+
exports.isValidCoords = isValidCoords;
|
|
4055
|
+
exports.isValidPiece = isValidPiece;
|
|
4056
|
+
exports.isValidPosition = isValidPosition;
|
|
4057
|
+
exports.isValidSquare = isValidSquare$1;
|
|
4058
|
+
exports.parseAnimation = parseAnimation;
|
|
4059
|
+
exports.parseTime = parseTime;
|
|
4060
|
+
exports.rafThrottle = rafThrottle;
|
|
4061
|
+
exports.resetTransform = resetTransform;
|
|
4062
|
+
exports.setTransform = setTransform;
|
|
4063
|
+
exports.throttle = throttle;
|
|
4064
|
+
exports.validateConfig = validateConfig;
|
|
4065
|
+
exports.validateFen = validateFen;
|
|
4066
|
+
exports.validateFenFormat = validateFenFormat;
|
|
4067
|
+
|
|
4068
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4069
|
+
|
|
4070
|
+
return exports;
|
|
4071
|
+
|
|
4072
|
+
})({});
|