Spaces:
Running
Running
File size: 2,781 Bytes
e16348e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | /**
* gameState.js: URL-hash sharing and persisted game state
*
* The hash is rewritten on every position change so the address bar stays
* share-able, and is read back on load (and on hashchange) to restore a
* shared link. Persisting the full move tree to localStorage additionally
* lets a round-trip through a different route (e.g. /admin, which has no
* #fen= of its own) restore the board position and PGN panel together.
*/
import { VARIANTS } from './board.js';
import * as Storage from './storage.js';
export function writeHash(fen, variant) {
try {
let hash = '#fen=' + encodeURIComponent(fen);
if (variant === VARIANTS.CHESS960) hash += '&variant=' + VARIANTS.CHESS960;
history.replaceState(null, '', hash);
} catch { /* sandboxed context */ }
}
export function readHashFen() {
try {
const m = location.hash.match(/[#&]fen=([^&]+)/);
return m ? decodeURIComponent(m[1]) : null;
} catch { return null; }
}
// Returns VARIANTS.CHESS960 / VARIANTS.STANDARD, or null (Standard) if the
// hash has no (or an unrecognized) variant param. Never inferred from the
// FEN itself.
export function readHashVariant() {
try {
const m = location.hash.match(/[#&]variant=([^&]+)/);
if (!m) return null;
const v = decodeURIComponent(m[1]);
if (v === VARIANTS.CHESS960) return VARIANTS.CHESS960;
if (v === VARIANTS.STANDARD) return VARIANTS.STANDARD;
return null;
} catch { return null; }
}
const _LS_GAME = 'chesstb_last_game';
export function saveGameState(history, startFen, variant) {
Storage.writeJson(_LS_GAME, {
variant,
startFen,
nodes: history.nodes,
rootChildren: history.rootChildren,
rootActiveChild: history.rootActiveChild,
currentId: history.currentId,
});
}
export function readLastGame() {
const parsed = Storage.readJson(_LS_GAME);
if (!parsed || typeof parsed.startFen !== 'string' || !Array.isArray(parsed.nodes)) {
return null;
}
parsed.variant = parsed.variant === VARIANTS.CHESS960 ? VARIANTS.CHESS960 : VARIANTS.STANDARD;
const node = parsed.nodes[parsed.currentId];
parsed.currentFen = (!node || typeof node.fen !== 'string') ? parsed.startFen : node.fen;
return parsed;
}
// Client-side mirror of the backend's own FEN padding (app.py's
// _normalize_fen): pads a partial FEN out to all six fields with the
// standard defaults.
export function normalizeFen(s) {
const trimmed = s.trim();
const defaults = ['8/8/8/8/8/8/8/8', 'w', '-', '-', '0', '1'];
const parts = trimmed ? trimmed.split(/\s+/) : [];
while (parts.length < 6) parts.push(defaults[parts.length]);
return parts.slice(0, 6).join(' ');
}
|