// Save this code as content_script.js
// You can use a blank Notepad file on windows if you don't have a script editor
// Place in a folder created only for this extension
function wordleBtn() {
// --- UTILITY FUNCTIONS ---
const qS = e => document.querySelector(e);
const log = e => console.log(e);
// --- GLOBAL VARIABLES ---
let storedGameNumber = null;
let boardVisibleTimer = null; // Timer for the 10-second check
// Shows a fallback popup with the results in a textarea ONLY if clipboard fails.
function showFallbackPopup(text) {
const overlay = document.createElement('div');
const modal = document.createElement('div');
const textArea = document.createElement('textarea');
const buttonContainer = document.createElement('div');
const copyButton = document.createElement('button');
const closeButton = document.createElement('button');
overlay.id = 'wordle-bbcode-overlay';
modal.id = 'wordle-bbcode-modal';
textArea.value = text;
copyButton.textContent = 'COPY';
closeButton.textContent = 'CLOSE';
buttonContainer.append(copyButton, closeButton);
modal.append(textArea, buttonContainer);
overlay.append(modal);
const styles = `
#wordle-bbcode-overlay { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background-color: rgba(0, 0, 0, 0.3); display: flex; justify-content: center; align-items: center; z-index: 10000; }
#wordle-bbcode-modal { background: var(--color-background, #FFF); color: var(--color-tone-1, #000); padding: 25px; border-radius: 8px; box-shadow: 0 5px 15px rgba(0,0,0,0.2); width: 90%; max-width: 500px; height: 500px; display: flex; flex-direction: column; gap: 15px; }
#wordle-bbcode-modal textarea { flex-grow: 1; resize: vertical; font-family: monospace; font-size: 14px; padding: 10px; box-sizing: border-box; background: var(--color-background-elevated, #F3F3F3); color: var(--color-tone-1, #000); border: 1px solid var(--color-tone-4, #CCC); }
#wordle-bbcode-modal div { display: flex; justify-content: flex-end; gap: 10px; }
#wordle-bbcode-modal button { padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; font-weight: bold; transition: background-color 0.2s; }
#wordle-bbcode-modal button:nth-of-type(1) { background-color: #538d4e; color: white; }
#wordle-bbcode-modal button:nth-of-type(1):hover { background-color: #6aaa64; }
#wordle-bbcode-modal button:nth-of-type(2) { background-color: var(--color-tone-4, #CCC); color: var(--color-tone-1, #000); }
#wordle-bbcode-modal button:nth-of-type(2):hover { background-color: var(--color-tone-3, #DDD); }
`;
const styleSheet = document.createElement("style");
styleSheet.id = 'wordle-bbcode-styles';
styleSheet.innerText = styles;
document.head.appendChild(styleSheet);
function closeModal() {
const overlayEl = document.getElementById('wordle-bbcode-overlay');
const styleEl = document.getElementById('wordle-bbcode-styles');
if (overlayEl) document.body.removeChild(overlayEl);
if (styleEl) document.head.removeChild(styleEl);
}
closeButton.addEventListener('click', closeModal);
overlay.addEventListener('click', (e) => {
if (e.target === overlay) closeModal();
});
copyButton.addEventListener('click', () => {
textArea.select();
navigator.clipboard.writeText(textArea.value).then(() => closeModal());
});
document.body.appendChild(overlay);
textArea.focus();
}
// Extracts results.
function extractWordleResults() {
const gameNumber = storedGameNumber || '????';
const gameContext = `Wordle ${gameNumber}`;
const allGameRows = document.querySelectorAll('#wordle-app-game [aria-label^="Row "]');
if (allGameRows.length === 0) {
console.error("Wordle board not found.");
return null;
}
let count = 0;
for (const row of allGameRows) {
const firstTile = row.querySelector('[aria-roledescription="tile"]');
if (firstTile && firstTile.textContent && firstTile.getAttribute('data-state') !== 'empty') {
count++;
} else {
break;
}
}
if (count === 0) return null;
const lastGuessRow = allGameRows[count - 1];
const lastTiles = lastGuessRow.querySelectorAll('[aria-roledescription="tile"]');
const isWin = Array.from(lastTiles).every(tile => tile.getAttribute('data-state') === 'correct');
const score = (count === 6 && !isWin) ? 'X/6' : `${count}/6`;
const emojiGrid = [];
const tableRows = [];
Array.from(allGameRows).slice(0, count).forEach(row => {
const tiles = row.querySelectorAll('[aria-roledescription="tile"]');
const rowEmojis = [];
const tableCells = [];
tiles.forEach(tile => {
const letter = tile.textContent.toUpperCase() || ' ';
const state = tile.getAttribute('data-state');
let coloredLetter;
if (state === 'correct') {
rowEmojis.push('🟩');
coloredLetter = `[COLOR=rgb(106, 170, 100)]${letter}[/COLOR]`;
} else if (state === 'present') {
rowEmojis.push('🟨');
coloredLetter = `[COLOR=rgb(250, 197, 28)]${letter}[/COLOR]`;
} else {
rowEmojis.push('⬛');
coloredLetter = `[COLOR=rgb(170, 170, 170)]${letter}[/COLOR]`;
}
tableCells.push(`[td width="20%"][CENTER][B]${coloredLetter}[/B][/CENTER][/td]`);
});
emojiGrid.push(rowEmojis.join(''));
tableRows.push(`[TR]${tableCells.join('')}[/TR]`);
});
return `${gameContext} ${score}\n${emojiGrid.join('\n')}\n\n[SPOILER="spoiler: actual guesses"][TABLE width="50%"]${tableRows.join('')}[/TABLE][/SPOILER]`;
}
function addShareButton() {
const toolbar = qS('.Toolbar-module_toolbar__DGjo1');
if (!toolbar || document.getElementById('bbcode-share-button')) return;
const button = document.createElement('button');
button.type = 'button';
button.className = 'ToolbarItem-module_toolbar_item__xrBr_';
button.id = 'bbcode-share-button';
button.setAttribute('aria-label', 'Share Wordle Results as XenForo');
const neonGreen = "#417a3c";
button.innerHTML = `<div class="Icon-module_iconWrapper__ZfKPm"><svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 95.71 122.88" style="enable-background:new 0 0 95.71 122.88" xml:space="preserve" width="20px" height="30px"><path fill="${neonGreen}" d="M63.33,12.26c-0.3,0-0.56-0.04-0.82-0.13c-1.33,0-2.45-1.08-2.45-2.45V4.87H36.33v4.82c0,1.24-0.99,2.32-2.2,2.41 c-0.26,0.09-0.56,0.13-0.86,0.13h-8.94v9.97h46.82v-9.98h-7.91L63.33,12.26L63.33,12.26L63.33,12.26z M17.02,101.49 c-0.67-0.99-0.4-2.34,0.6-3.01c0.99-0.67,2.34-0.41,3.01,0.6l1.19,1.75l4.69-5.71c0.76-0.93,2.13-1.06,3.05-0.3 c0.93,0.76,1.06,2.13,0.3,3.05l-6.5,7.9c-0.14,0.18-0.32,0.35-0.52,0.49c-0.99,0.67-2.34,0.4-3.01-0.6L17.02,101.49L17.02,101.49 L17.02,101.49z M40.3,101.63c-1.33,0-2.45-1.08-2.45-2.45c0-1.33,1.08-2.45,2.45-2.45h35.81c1.33,0,2.45,1.08,2.45,2.45 c0,1.33-1.08,2.45-2.45,2.45H40.3L40.3,101.63L40.3,101.63z M17.02,79.4c-0.67-0.99-0.4-2.34,0.6-3.01 c0.99-0.67,2.34-0.41,3.01,0.6l1.19,1.75l4.69-5.71c0.76-0.93,2.13-1.06,3.05-0.3c0.93,0.76,1.06,2.13,0.3,3.05l-6.5,7.9 c-0.14,0.18-0.32,0.35-0.52,0.49c-0.99,0.67-2.34,0.4-3.01-0.6L17.02,79.4L17.02,79.4L17.02,79.4z M40.3,79.54 c-1.33,0-2.45-1.08-2.45-2.45c0-1.33,1.08-2.45,2.45-2.45h35.81c1.33,0,2.45,1.08,2.45,2.45c0,1.33-1.08,2.45-2.45,2.45H40.3 L40.3,79.54L40.3,79.54z M17.36,49.24h13.45l4.39-8.89l8.3,11.97l8.44-16.46l8.77,17.18l3.39-3.11l1.76-0.69h12.49v5.2H66.86 l-7.68,7.05l-7.27-14.24l-7.75,15.12l-8.21-11.84l-1.93,3.91H17.36V49.24L17.36,49.24z M4.82,118.06h85.94V19.13 c0-0.13-0.04-0.3-0.17-0.39c-0.09-0.09-0.21-0.17-0.39-0.17H76.1v4.9c0,0.99-0.39,1.89-1.08,2.58c-0.65,0.65-1.55,1.08-2.58,1.08 H23.13c-0.99,0-1.94-0.43-2.58-1.08c-0.09-0.09-0.13-0.17-0.21-0.26c-0.52-0.65-0.86-1.47-0.86-2.32v-4.9H5.38 c-0.13,0-0.3,0.04-0.39,0.17C4.91,18.83,4.82,19,4.82,19.13V118.06L4.82,118.06z M93.31,122.77v0.11H0v-0.11v-4.71V19.13 c0-1.5,0.6-2.83,1.59-3.83s2.32-1.59,3.83-1.59h14.1v-2.67c0-0.99,0.39-1.89,1.08-2.58c0.65-0.65,1.55-1.08,2.58-1.08h8.35V4.04 c0-1.12,0.47-2.11,1.2-2.83C33.45,0.47,34.44,0,35.56,0h25.41c1.12,0,2.11,0.47,2.83,1.2c0.73,0.73,1.21,1.72,1.21,2.83v3.35h7.53 c0.99,0,1.89,0.43,2.58,1.08c0.65,0.65,1.08,1.59,1.08,2.58v2.67l14.1,0c1.5,0,2.83,0.6,3.83,1.59c0.99,0.99,1.59,2.32,1.59,3.83 v103.63H93.31L93.31,122.77z"/></svg></div>`;
button.addEventListener('click', () => {
const results = extractWordleResults();
if (!results) {
alert("Could not extract Wordle results. The board might not be visible.");
return;
}
navigator.clipboard.writeText(results).then(() => {
const gameToast = qS('.Toast-module_toast__222_T');
if (gameToast) {
gameToast.textContent = 'XenForo Results Copied!';
gameToast.style.display = 'flex';
setTimeout(() => {
gameToast.style.display = 'none';
}, 2000);
} else {
alert('Wordle XenForo results copied to clipboard!');
}
}).catch(err => {
console.error('Clipboard write failed, showing fallback popup.', err);
showFallbackPopup(results);
});
});
if (toolbar) toolbar.querySelector('menu').appendChild(button);
}
// --- MAIN EXECUTION ---
// Observer 1: Watches for the toolbar to add our share button.
const toolbarObserver = new MutationObserver((mutationsList, obs) => {
if (qS('.Toolbar-module_toolbar__DGjo1')) {
addShareButton();
obs.disconnect(); // Stop watching once the button is added.
}
});
// A single function to try finding the game number from the welcome screen.
function tryGetWelcomeNumber() {
const numberP = document.querySelector('.Welcome-module_contentWelcomeMain__O6vot p.Welcome-module_wordleMeta__P_0lJ');
if (numberP && numberP.textContent.startsWith('No. ')) {
const num = numberP.textContent.split('No. ')[1];
if (num) {
// Your formatting is preserved
storedGameNumber = Intl.NumberFormat('en-US').format(num.trim());
// log(`Game number ${storedGameNumber} captured from Welcome screen.`);
return true; // Indicate success
}
}
return false; // Indicate failure
}
// Observer 2: Proactively watches for the Welcome screen. This is our primary method.
const welcomeObserver = new MutationObserver((mutationsList, obs) => {
if (tryGetWelcomeNumber()) {
obs.disconnect(); // If we found it, we're done with this observer.
}
});
// Observer 3: Watches for the game board to implement the 10-second fallback.
const gameBoardObserver = new MutationObserver((mutationsList, obs) => {
const board = qS('#wordle-app-game');
if (board && !boardVisibleTimer) {
// The board has just appeared. Start the 10-second timer.
boardVisibleTimer = setTimeout(() => {
// After 10 seconds, run this code:
if (!storedGameNumber) {
// If we still don't have a number, make one last attempt.
log('10 seconds elapsed. Making final attempt to find Welcome Screen number.');
tryGetWelcomeNumber();
}
// Regardless of success, we are done with this observer.
obs.disconnect();
}, 10000); // 10 seconds
} else if (!board && boardVisibleTimer) {
// The board has disappeared before the 10 seconds were up. Reset the timer.
clearTimeout(boardVisibleTimer);
boardVisibleTimer = null;
}
});
// Start all observers. They will disconnect themselves when their job is done.
toolbarObserver.observe(document.body, {
childList: true,
subtree: true
});
welcomeObserver.observe(document.body, {
childList: true,
subtree: true
});
gameBoardObserver.observe(document.body, {
childList: true,
subtree: true
});
}
wordleBtn();