var typingMode = 'vocab'; var typingItems = []; var typingIndex = 0; var typingStats = { correct: 0, errors: 0 }; var typed = ''; var KEY_ROWS = [ ['1','2','3','4','5','6','7','8','9','0'], ['q','w','e','r','t','y','u','i','o','p'], ['a','s','d','f','g','h','j','k','l','ñ'], ['z','x','c','v','b','n','m',',','.',';'], ['á','é','í','ó','ú','ü','¿','¡',':','?','!',' '] ]; function escTyping(s) { var div = document.createElement('div'); div.textContent = s == null ? '' : String(s); return div.innerHTML; } function currentCategory() { var id = document.getElementById('category-select').value; return window.TYPING_DATA[typingMode].categories.find(function(c) { return c.id === id; }); } function renderCategories() { var data = window.TYPING_DATA[typingMode]; var select = document.getElementById('category-select'); select.innerHTML = data.categories.map(function(cat) { return ''; }).join(''); } function startTyping() { var category = currentCategory(); if (!category) return; var source = category.items.map(function(item, idx) { return Object.assign({}, item, { id: idx + 1 }); }); if (document.getElementById('order-select').value === 'random') { for (var i = source.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = source[i]; source[i] = source[j]; source[j] = t; } } var count = document.getElementById('count-select').value; typingItems = count === 'all' ? source : source.slice(0, parseInt(count, 10) || 10); typingIndex = 0; typingStats = { correct: 0, errors: 0 }; typed = ''; document.getElementById('typing-input').style.display = ''; document.getElementById('setup-view').style.display = 'none'; document.getElementById('practice-view').style.display = 'block'; renderPractice(); } function renderPractice() { if (typingIndex >= typingItems.length) { renderFinish(); return; } var item = typingItems[typingIndex]; var target = item.es; var targetHtml = ''; for (var i = 0; i < target.length; i++) { var ch = escTyping(target[i]); if (i < typed.length) { targetHtml += '' + ch + ''; } else if (i === typed.length) { targetHtml += '' + ch + ''; } else { targetHtml += ch; } } document.getElementById('target-text').innerHTML = targetHtml; document.getElementById('chinese-text').textContent = item.zh || ''; document.getElementById('progress-text').textContent = (typingIndex + 1) + ' / ' + typingItems.length; var totalKeys = typingStats.correct + typingStats.errors; document.getElementById('accuracy-text').textContent = '正确按键 ' + typingStats.correct + ',错误 ' + typingStats.errors + ',正确率 ' + (totalKeys ? Math.round(typingStats.correct * 100 / totalKeys) : 100) + '%'; document.getElementById('progress-fill').style.width = (typingIndex * 100 / typingItems.length) + '%'; var input = document.getElementById('typing-input'); input.value = typed; renderNextKey(target); renderKeyboard(target); setTimeout(function() { input.focus(); }, 50); } function renderNextKey(target) { var next = target[typed.length]; document.getElementById('next-key').innerHTML = typed.length >= target.length ? '已完成' : '下一键:' + escTyping(next) + ''; } function renderTypingAccuracy() { var totalKeys = typingStats.correct + typingStats.errors; document.getElementById('accuracy-text').textContent = '正确按键 ' + typingStats.correct + ',错误 ' + typingStats.errors + ',正确率 ' + (totalKeys ? Math.round(typingStats.correct * 100 / totalKeys) : 100) + '%'; } function renderKeyboard(target) { var next = target[typed.length] || ''; var container = document.getElementById('keyboard'); container.innerHTML = KEY_ROWS.map(function(row) { return '
完成 ' + typingItems.length + ' 个,正确率 ' + accuracy + '%