import { Application, Controller } from "https://unpkg.com/@hotwired/stimulus/dist/stimulus.js"; import { GameState, getGameState, setGameState, calculateScore } from "./models.js"; function emitGameStateEvent(details) { // window.setTimeout(() => { let ev = new CustomEvent("gamestatechanged", { detail: details }); window.dispatchEvent(ev); // }, 1); } window.Stimulus = Application.start(); Stimulus.register("scorecard", class extends Controller { static targets = ["prevailing"]; initialize() { } connect() { // this._rebuildTable(); // this.element.classList.remove("hidden"); } handleGameState(ev) { switch (ev.detail.mode) { case "newgame": case "endround": this.element.classList.add("hidden"); break; case "startgame": case "nextround": this._rebuildTable(); this.element.classList.remove("hidden"); break; } } endRound(ev) { ev.preventDefault(); emitGameStateEvent({mode: "endround"}); } endGame(ev) { ev.preventDefault(); if (!confirm("Are you sure you want to end the game?")) { return; } emitGameStateEvent({mode: "newgame"}); } _rebuildTable() { let gameState = getGameState(); let tbl = document.createElement("table"); tbl.classList.add("scorecard"); let thead = document.createElement("thead"); let thr = document.createElement("tr"); let headRows = gameState.players.map(player => { let th = document.createElement("th"); th.textContent = player.name + " (" + player.wind + ")"; return th; }); thr.append(...headRows); thead.append(thr); tbl.append(thead); let tbody = document.createElement("tbody"); for (let r of gameState.rounds) { let tr = document.createElement("tr"); for (let c of r) { let td = document.createElement("td"); td.textContent = c.s; if (c.w) { td.classList.add("winner"); td.textContent += " 🏆"; } tr.append(td); } tbody.append(tr); } tbl.append(tbody); let tfoot = document.createElement("tfoot"); for (let t of gameState.playerTotals()) { let td = document.createElement("td"); td.textContent = t; tfoot.append(td); } tbl.append(tfoot); this.element.querySelector("table.scorecard").replaceWith(tbl); this.prevailingTarget.textContent = `Prevailing: ${gameState.prevaling}`; } }); Stimulus.register("newgame", class extends Controller { static targets = ["playerName"]; connect() { this.element.classList.remove("hidden"); } handleGameState(ev) { switch (ev.detail.mode) { case "startgame": case "endround": case "nextround": this.element.classList.add("hidden"); break; case "newgame": this.element.classList.remove("hidden"); break; } } startGame() { let players = []; this.playerNameTargets.forEach(el => { if (el.value != "") { players.push(el.value); } }); setGameState(GameState.newGame(players)); this.element.classList.add("hidden"); emitGameStateEvent({mode: "startgame"}); } }); Stimulus.register("endround", class extends Controller { static targets = ["form", "input", "wind"]; connect() { // this.element.classList.remove("hidden"); } handleGameState(ev) { switch (ev.detail.mode) { case "startgame": case "nextround": case "newgame": this.element.classList.add("hidden"); break; case "endround": this._prepForms(); this.element.classList.remove("hidden"); break; } } updatePreview(ev) { ev.preventDefault(); let scoreExprs = this._readScoreExprs(); let nextRound = getGameState().determineNextRound(scoreExprs); for (let i in nextRound.roundScores) { let previewElem = this.element.querySelector(`.preview[data-player="${i}"]`); previewElem.textContent = nextRound.roundScores[i].score; if (parseInt(i) === nextRound.roundWinner) { previewElem.textContent += " 🏆"; } } if (nextRound.windsBump) { this.windTarget.textContent = `${getGameState().players[nextRound.nextRoundEast].name} will be East next round`; } else { this.windTarget.textContent = `${getGameState().players[nextRound.nextRoundEast].name} will remain East next round`; } } goBack(ev) { emitGameStateEvent({mode: "startgame"}); } nextRound(ev) { ev.preventDefault(); let scoreExprs = this._readScoreExprs(); getGameState().startNextRound(scoreExprs); emitGameStateEvent({mode: "nextround"}); } _prepForms() { let newFormElems = getGameState().players.map((player, i) => { let outerDiv = document.createElement("div"); let label = document.createElement("label"); label.textContent = player.name + " (" + player.wind + ")"; label.setAttribute("for", `player-${i}`); let div = document.createElement("div"); div.classList.add("score-input-group"); let input = document.createElement("input"); input.name = `player-${i}`; input.dataset["endroundTarget"] = "input"; input.dataset["action"] = "keyup->endround#updatePreview"; input.dataset["player"] = i; let preview = document.createElement("div"); preview.classList.add("preview"); preview.textContent = "0"; preview.dataset["player"] = i; div.append(input, preview); outerDiv.append(label, div); return outerDiv; }); this.formTarget.replaceChildren(...newFormElems); } _readScoreExprs() { let scoreExprs = []; for (let playerIndex in getGameState().players) { let thisScoreExpr = this.formTarget.querySelector(`input[data-player="${playerIndex}"]`).value; scoreExprs.push(thisScoreExpr); } return scoreExprs; } });