Some enhancements of the Wordle game.
// ==UserScript==// @name Wordle Tools// @namespace CCCC_David// @version 0.2.0// @description Some enhancements of the Wordle game.// @author CCCC_David// @match https://www.powerlanguage.co.uk/wordle/// @match https://www.nytimes.com/games/wordle/index.html// @grant none// @license MIT// ==/UserScript==(async () => {'use strict';const SUCCESS_MSG_TIMEOUT = 3000;const allowedPolicy = window.trustedTypes?.createPolicy?.('allowedPolicy', {createHTML: (x) => x});const createTrustedHTML = (html) => (allowedPolicy ? allowedPolicy.createHTML(html) : html);let puzzleList = null;const getPuzzleList = async () => {if (puzzleList) {return puzzleList;}try {for (const el of document.getElementsByTagName('script')) {const scriptSrc = el.src;if (/\bmain\.\w+\.js$/u.test(scriptSrc ?? '')) {// eslint-disable-next-line no-await-in-loopconst res = await fetch(scriptSrc, {method: 'GET',mode: 'same-origin',redirect: 'follow',});// eslint-disable-next-line no-await-in-loopconst jsCode = await res.text();puzzleList = JSON.parse(jsCode.match(/\["cigar".*?"shave"\]/u)[0]);return puzzleList;}}} catch (e) {// eslint-disable-next-line no-consoleconsole.error(e);}return null;};const appendPuzzleIdToTitle = (gameAppElement, puzzleId) => {const puzzleIdInTitleSpan = document.createElement('span');puzzleIdInTitleSpan.id = 'wordle-tools-puzzle-id-in-title';puzzleIdInTitleSpan.innerText = puzzleId;gameAppElement.$game.parentElement.querySelector('div[class="title"]').appendChild(puzzleIdInTitleSpan);};const clearGameState = (gameAppElement) => {localStorage.removeItem('gameState');localStorage.removeItem('nyt-wordle-state');gameAppElement.gameStatus = 'IN_PROGRESS';gameAppElement.canInput = true;gameAppElement.boardState = new Array(6).fill('');gameAppElement.evaluations = new Array(6).fill(null);gameAppElement.letterEvaluations = {};gameAppElement.rowIndex = 0;gameAppElement.tileIndex = 0;gameAppElement.restoringFromLocalStorage = false;for (const row of gameAppElement.$game.getElementsByTagName('game-row')) {row.removeAttribute('letters');for (const tile of row.shadowRoot.querySelectorAll('game-tile')) {tile.removeAttribute('letter');tile.removeAttribute('evaluation');tile.removeAttribute('reveal');}}for (const button of gameAppElement.$keyboard.shadowRoot.querySelectorAll('button')) {button.removeAttribute('data-state');button.classList.remove('fade');}gameAppElement.$game.querySelector('#game-toaster').innerHTML = '';};const clearStatistics = () => {localStorage.removeItem('statistics');localStorage.removeItem('nyt-wordle-statistics');};const jumpToPuzzleId = (gameAppElement, settingsShadowRoot, puzzleId) => {clearGameState(gameAppElement);gameAppElement.dayOffset = puzzleId;gameAppElement.solution = puzzleList[puzzleId % puzzleList.length];gameAppElement.$game.parentElement.querySelector('#wordle-tools-puzzle-id-in-title').innerText = puzzleId;settingsShadowRoot.getElementById('puzzle-number').innerText = `#${puzzleId}`;};const handleGameAppElement = async (gameAppElement) => {if (!gameAppElement) {return;}window.gameApp = gameAppElement;await getPuzzleList();const appendSettingsItems = (gameSettingsElement) => {if (!gameSettingsElement) {return;}const settingsShadowRoot = gameSettingsElement.shadowRoot;const settingsSection = settingsShadowRoot.querySelector('div[class="sections"] > section');const showSuccessMsg = (message, insertBeforeNode, enableElements) => {const successMsgElement = document.createElement('span');successMsgElement.innerText = message;successMsgElement.style.color = 'var(--color-correct)';insertBeforeNode.parentElement.insertBefore(successMsgElement, insertBeforeNode);setTimeout(() => {successMsgElement.remove();for (const el of enableElements) {el.disabled = false;}}, SUCCESS_MSG_TIMEOUT);};const jumpItem = document.createElement('div');settingsSection.appendChild(jumpItem);jumpItem.outerHTML = createTrustedHTML(`<div class="setting"><div class="text"><div class="title">Jump to Puzzle #</div></div><div class="control"><input type="text" id="wordle-tools-jump-target-id" style="width: 3em;"><button id="wordle-tools-jump-to-puzzle">Jump</button></div></div>`);const jumpButton = settingsShadowRoot.getElementById('wordle-tools-jump-to-puzzle');const jumpInput = settingsShadowRoot.getElementById('wordle-tools-jump-target-id');jumpInput.value = gameAppElement.dayOffset;jumpButton.addEventListener('click', (e) => {const button = e.target;const inputBox = button.parentElement.querySelector('input');const puzzleId = parseInt(inputBox.value, 10);if (Number.isNaN(puzzleId) || puzzleId < 0) {inputBox.value = gameAppElement.dayOffset;return;}button.disabled = true;inputBox.disabled = true;inputBox.value = puzzleId;jumpToPuzzleId(gameAppElement, settingsShadowRoot, puzzleId);showSuccessMsg('Jumped to ', inputBox, [button, inputBox]);});jumpInput.addEventListener('keydown', (e) => {if (e.key === 'Enter') {jumpButton.click();}});const clearStateItem = document.createElement('div');settingsSection.appendChild(clearStateItem);clearStateItem.outerHTML = createTrustedHTML(`<div class="setting"><div class="text"><div class="title">Clear Current Game State</div></div><div class="control"><button id="wordle-tools-clear-game-state">Clear</button></div></div>`);settingsShadowRoot.getElementById('wordle-tools-clear-game-state').addEventListener('click', (e) => {const button = e.target;button.disabled = true;clearGameState(gameAppElement);showSuccessMsg('Cleared ', button, [button]);});const clearStatsItem = document.createElement('div');settingsSection.appendChild(clearStatsItem);clearStatsItem.outerHTML = createTrustedHTML(`<div class="setting"><div class="text"><div class="title">Clear Game Statistics</div></div><div class="control"><button id="wordle-tools-clear-statistics">Clear</button></div></div>`);settingsShadowRoot.getElementById('wordle-tools-clear-statistics').addEventListener('click', (e) => {const button = e.target;button.disabled = true;clearStatistics();showSuccessMsg('Cleared ', button, [button]);});const feedbackSection = settingsShadowRoot.querySelectorAll('div[class="sections"] > section')[1];const wordleToolsMarker = document.createElement('div');feedbackSection.appendChild(wordleToolsMarker);wordleToolsMarker.outerHTML = createTrustedHTML(`<div class="setting"><div class="text"><div class="title">Wordle Tools v0.2.0 Enabled</div></div></div>`);};const gameSettingsObserver = new MutationObserver((mutationsList) => {for (const mutation of mutationsList) {if (mutation.type === 'childList') {for (const el of mutation.addedNodes) {if (el.nodeName.toLowerCase() === 'game-settings') {appendSettingsItems(el);}}}}});gameSettingsObserver.observe(gameAppElement.$game, {subtree: true,childList: true,});appendSettingsItems(gameAppElement.$game.getElementsByTagName('game-settings')[0]);appendPuzzleIdToTitle(gameAppElement, gameAppElement.dayOffset);};const gameAppObserver = new MutationObserver(async (mutationsList) => {for (const mutation of mutationsList) {if (mutation.type === 'childList') {for (const el of mutation.addedNodes) {if (el.nodeName.toLowerCase() === 'game-app') {// eslint-disable-next-line no-await-in-loopawait handleGameAppElement(el);}}}}});gameAppObserver.observe(document.documentElement, {subtree: true,childList: true,});await handleGameAppElement(document.getElementsByTagName('game-app')[0]);})();