diff --git a/src/Game/base.js b/src/Game/base.js index c31a9b2d..b2faf70d 100644 --- a/src/Game/base.js +++ b/src/Game/base.js @@ -119,7 +119,7 @@ export default class GameBase { const handleError = (error) => { if (this.onError) { - this.onError(error, this.plies.length - 1); + this.onError(error, this.plies.length); } else { throw error; } diff --git a/src/Game/index.js b/src/Game/index.js index e4ba1d14..e6c530f8 100644 --- a/src/Game/index.js +++ b/src/Game/index.js @@ -13,31 +13,45 @@ export default class Game extends Aggregation( GameMutations, GameUndo ) { - static validate(ptn, silent = false) { - let result = true; - let game; - try { - // Parse the game - game = new Game({ - ptn, - state: { plyIndex: 0 }, - onError: (error, plyID) => { - result = error.message || error; - if (!silent) { - console.warn("Encountered an error at plyID:", plyID); - console.warn(error); + static validate(ptn, silent = false, multiple = false) { + const games = multiple ? Game.split(ptn) : [ptn]; + let isValid = true; + + const _validate = (ptn, i) => { + let game; + try { + // Parse the game + game = new Game({ + ptn, + state: { plyIndex: 0 }, + onError: (error, plyID) => { + isValid = isValid && (error.message || error); + if (!silent) { + console.warn( + `Encountered an error at ${ + games.length > 1 ? "Game " + (i + 1) + ", " : "" + }plyID: ${plyID}` + ); + console.warn(error); + } + }, + }); + + // Navigate through each branch + Object.values(game.branches).forEach((ply) => { + if (isValid === true) { + game.board.goToPly(ply.id, true); + game.board.last(); } - }, - }); + }); + } catch (error) {} + }; - // Navigate through each branch - Object.values(game.branches).forEach((ply) => { - if (result === true) { - game.board.goToPly(ply.id, true); - game.board.last(); - } - }); - } catch (error) {} - return result; + if (games) { + games.forEach(_validate); + } else { + _validate(ptn); + } + return isValid; } } diff --git a/src/components/controls/PTNEditor.vue b/src/components/controls/PTNEditor.vue index e05d641b..8da14261 100644 --- a/src/components/controls/PTNEditor.vue +++ b/src/components/controls/PTNEditor.vue @@ -30,7 +30,11 @@ export default { header: "", rules: [ (moves) => { - const result = Game.validate(this.header + moves); + const result = Game.validate( + this.header + moves, + false, + this.isNewGame + ); if (result === true) { this.$emit("error", ""); return true; diff --git a/src/dialogs/AddGame.vue b/src/dialogs/AddGame.vue index 19d5278c..b26136fd 100644 --- a/src/dialogs/AddGame.vue +++ b/src/dialogs/AddGame.vue @@ -217,16 +217,31 @@ export default { } }, async clipboardCreate(ptn) { - let game; - try { - game = new Game({ ptn }); - } catch (error) { - console.error(error); - } + const games = Game.split(ptn); - game.warnings.forEach((warning) => this.notifyWarning(warning)); + const _createGame = (ptn, i) => { + try { + const game = new Game({ ptn }); + game.warnings.forEach((warning) => { + console.log(i, warning); + this.notifyWarning(warning); + }); + if (games.length > 1) { + game.name += " - " + this.$tc("Game x", i + 1); + } + games[i] = game; + } catch (error) { + console.error(error); + } + }; + + if (games) { + games.forEach(_createGame); + } else { + _createGame(ptn); + } - await this.$store.dispatch("game/ADD_GAME", game); + await this.$store.dispatch("game/ADD_GAMES", { games }); this.close(); }, playTak() { diff --git a/src/i18n/en-us/index.js b/src/i18n/en-us/index.js index 6e49e970..e13cb268 100644 --- a/src/i18n/en-us/index.js +++ b/src/i18n/en-us/index.js @@ -81,6 +81,7 @@ export default { "From Center": "From Center", "Full Link": "Full Link", Fullscreen: "Fullscreen", + "Game x": "Game {count}", "Game Info": "Game Info", "Game Notifications": "Game Notifications", "Game x closed": 'Closed "{game}"', diff --git a/src/store/game/actions.js b/src/store/game/actions.js index 27cfe546..17d70d99 100644 --- a/src/store/game/actions.js +++ b/src/store/game/actions.js @@ -120,7 +120,7 @@ export const IMPORT_FROM_CLIPBOARD = async function ({ dispatch }) { } catch (error) { console.error(error); } - let game; + let games = []; if (ptn) { if (/^\d+$/.test(ptn)) { // PlayTak game ID @@ -151,7 +151,7 @@ export const IMPORT_FROM_CLIPBOARD = async function ({ dispatch }) { if (!isEmpty(route.params)) { try { const params = parseURLparams(route); - game = new Game(params); + games[0] = new Game(params); await dispatch("ADD_GAME", game); return true; } catch (error) { @@ -160,9 +160,16 @@ export const IMPORT_FROM_CLIPBOARD = async function ({ dispatch }) { } } } - } else if (Game.validate(ptn, true) === true) { + } else if (Game.validate(ptn, true, true) === true) { // PTN - game = new Game({ ptn }); + games = Game.split(ptn); + games = games.map((ptn, i) => { + const game = new Game({ ptn }); + if (games.length > 1) { + game.name += " - " + i18n.tc("Game x", i + 1); + } + return game; + }); } else if (Ply.test(ptn) || Linenum.test(ptn)) { // Plies dispatch("INSERT_PLIES", { plies: ptn }); @@ -172,18 +179,18 @@ export const IMPORT_FROM_CLIPBOARD = async function ({ dispatch }) { let tps = new TPS(ptn); if (tps.isValid) { tps = tps.text; - game = new Game({ tags: { tps } }); + games[0] = new Game({ tags: { tps } }); } else { // JSON try { let tags = JSON.parse(ptn); - game = new Game({ tags }); + games[0] = new Game({ tags }); } catch (error) {} } } } - if (ptn && game) { - await dispatch("ADD_GAME", game); + if (ptn && games && games.length) { + await dispatch("ADD_GAMES", { games }); return true; } else { router.push({ name: "add", params: { tab: "load", type: "ptn" } }); @@ -494,7 +501,10 @@ export const OPEN_FILES = async function ({ dispatch, state }, files) { const name = file.name.replace(/(\.ptn|\.txt)+$/, ""); const games = Game.split(event.target.result); games.forEach((ptn, i) => { - parseGame(ptn, `${name} - Game ${i + 1}`); + parseGame( + ptn, + games.length > 1 ? name + " - " + i18n.t("Game x", i + 1) : name + ); }); }; reader.onerror = notifyError;