ARTICLE AD BOX
Problem
When I type a letter into a cell, the focus does not move to the next cell in the word.
After typing a letter, the entire input system becomes unresponsive — I can’t type more letters, delete them, or click on other cells.
It feels as if an event handler throws an error and stops all further execution.
I guess all problems are in renderGrid() but I don't know where exactly they are
(I have all html elements written correctly)
const GRID_ROWS = 10; const GRID_COLS = 10; const WORDS = [ // Across { word: 'READ', clue: 'To look at and comprehend written words', row: 0, col: 0, direction: 'across', id: 1 }, { word: 'EASY', clue: 'Not difficult', row: 2, col: 2, direction: 'across', id: 2 }, { word: 'NOTE', clue: 'A short written message', row: 4, col: 4, direction: 'across', id: 3 }, { word: 'GAME', clue: 'An activity for fun or competition', row: 6, col: 6, direction: 'across', id: 4 }, // Down { word: 'RENT', clue: 'To pay for the use of something', row: 0, col: 0, direction: 'down', id: 5 }, { word: 'DEAN', clue: 'A college official', row: 0, col: 2, direction: 'down', id: 6 }, { word: 'SONG', clue: 'A musical composition', row: 2, col: 4, direction: 'down', id: 7 }, { word: 'MEGA', clue: 'Very large', row: 4, col: 6, direction: 'down', id: 8 }, ]; let grid = []; let selectedWordId = null; let completedWords = new Set(); function createGrid() { grid = Array.from({ length: GRID_ROWS }, (_, r) => Array.from({ length: GRID_COLS }, (_, c) => ({ row: r, col: c, letter: null, value: '', words: [] })) ); WORDS.forEach(wordObj => { let r = wordObj.row, c = wordObj.col; for (let i = 0; i < wordObj.word.length; i++) { const cell = grid[r][c]; cell.letter = wordObj.word[i]; cell.words.push(wordObj.id); if (wordObj.direction === 'across') c++; else r++; } }); } function renderGrid() { const table = document.getElementById('crosswordGrid'); table.innerHTML = ''; for (let r = 0; r < GRID_ROWS; r++) { const tr = document.createElement('tr'); for (let c = 0; c < GRID_COLS; c++) { const cell = grid[r][c]; const td = document.createElement('td'); if (cell.letter) { const input = document.createElement('input'); input.type = 'text'; input.maxLength = 1; input.className = 'crossword-cell'; input.value = cell.value; input.dataset.row = r; input.dataset.col = c; input.onfocus = () => selectCell(r, c); input.oninput = e => handleInput(e, r, c); td.appendChild(input); } else { td.className = 'cell-blocked'; } tr.appendChild(td); } table.appendChild(tr); } } function renderClues() { const acrossDiv = document.getElementById('acrossClues'); const downDiv = document.getElementById('downClues'); acrossDiv.innerHTML = ''; downDiv.innerHTML = ''; WORDS.forEach(word => { const clueDiv = document.createElement('div'); clueDiv.className = 'clue' + (selectedWordId === word.id ? ' selected' : '') + (completedWords.has(word.id) ? ' completed' : ''); clueDiv.textContent = word.clue; clueDiv.onclick = () => selectWord(word.id); if (word.direction === 'across') acrossDiv.appendChild(clueDiv); else downDiv.appendChild(clueDiv); }); } function selectWord(wordId) { selectedWordId = wordId; renderClues(); // Focus first cell of the word const word = WORDS.find(w => w.id === wordId); if (word) { const input = document.querySelector(`input[data-row="${word.row}"][data-col="${word.col}"]`); if (input) input.focus(); } } function selectCell(row, col) { // Select the first word that uses this cell const cell = grid[row][col]; if (cell.words.length) { selectWord(cell.words[0]); } } function handleInput(e, row, col) { const val = e.target.value.toUpperCase(); if (!val.match(/^[A-Z]?$/)) { e.target.value = ''; return; } grid[row][col].value = val; checkWordsAtCell(row, col); renderClues(); updateScore(); if (val) { let word = null; if (selectedWordId) { word = WORDS.find(w => w.id === selectedWordId); } else { // Если слово не выбрано, выбираем первое из возможных для клетки const cell = grid[row][col]; if (cell.words.length) { word = WORDS.find(w => w.id === cell.words[0]); selectedWordId = cell.words[0]; renderClues(); } } if (word) { let nextRow = row; let nextCol = col; if (word.direction === 'across') nextCol++; else nextRow++; // Проверяем, есть ли следующая клетка в слове for (let i = 0; i < word.word.length; i++) { const r = word.row + (word.direction === 'down' ? i : 0); const c = word.col + (word.direction === 'across' ? i : 0); if (r === nextRow && c === nextCol) { const nextInput = document.querySelector(`input[data-row="${nextRow}"][data-col="${nextCol}"]`); if (nextInput) nextInput.focus(); break; } } } } } function checkWordsAtCell(row, col) { const cell = grid[row][col]; cell.words.forEach(wordId => { const word = WORDS.find(w => w.id === wordId); let r = word.row, c = word.col, correct = true; for (let i = 0; i < word.word.length; i++) { if (grid[r][c].value !== word.word[i]) { correct = false; break; } if (word.direction === 'across') c++; else r++; } if (correct) completedWords.add(wordId); }); } function updateScore() { document.getElementById('scoreDisplay').textContent = `Words Completed: ${completedWords.size}`; } function resetCrossword() { completedWords.clear(); selectedWordId = null; createGrid(); renderGrid(); renderClues(); updateScore(); } window.onload = () => { createGrid(); renderGrid(); renderClues(); updateScore(); };