/
dayekb
/
vibecoding_type_trainer
Обзор
Документация
Войти
/
dayekb
/
vibecoding_type_trainer
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
script.js
1 032 строки
54 KB
dayekb
upload files
06 сен 2025, 09:47
06 сен 2025, 09:47
239b2d1
Код
Авторство
О чём код?
class TypingTrainer { constructor() { this.currentLanguage = 'ru'; this.currentText = ''; this.userInput = ''; this.startTime = null; this.isPaused = false; this.isTyping = false; this.errors = 0; this.currentPosition = 0; this.difficulty = 'easy'; this.mode = 'practice'; // 'practice' или 'training' this.currentLesson = 0; this.lessonProgress = 0; this.maxErrors = 3; // Максимальное количество ошибок в режиме тренировки this.lessonFailed = false; this.isDarkTheme = false; // Тексты для упражнений this.texts = { ru: { easy: [ "Привет мир! Это простой текст для обучения слепой печати.", "Кот сидит на столе. Собака бежит по двору.", "Мама готовит обед. Папа читает газету.", "Дети играют во дворе. Птицы поют в саду.", "Книга лежит на полке. Ручка стоит в стакане." ], medium: [ "Современные технологии развиваются стремительными темпами. Каждый день появляются новые изобретения, которые меняют нашу жизнь.", "Программирование - это искусство создания программного обеспечения. Оно требует логического мышления и внимательности к деталям.", "Образование играет важную роль в развитии общества. Знания помогают людям адаптироваться к изменяющемуся миру.", "Природа прекрасна в любое время года. Весной распускаются цветы, летом зеленеет трава, осенью желтеют листья, зимой падает снег.", "Дружба - это одно из самых ценных человеческих отношений. Настоящие друзья всегда поддержат в трудную минуту." ], hard: [ "Квантовая механика представляет собой фундаментальную теорию, описывающую физические свойства природы на атомном и субатомном уровнях. Она является основой для понимания поведения материи и энергии в микроскопических масштабах.", "Синтаксический анализ естественного языка представляет собой сложную задачу, требующую глубокого понимания грамматических структур, семантических связей и контекстных зависимостей между словами и фразами.", "Экономическая теория изучает процессы производства, распределения и потребления товаров и услуг в условиях ограниченности ресурсов. Она помогает понять механизмы функционирования рыночной экономики.", "Философия науки исследует природу научного знания, методы научного познания и критерии научности. Она ставит вопросы о том, что такое истина, как мы можем её достичь и каковы границы человеческого познания.", "Алгоритмическая сложность является важным понятием в информатике, характеризующим эффективность алгоритмов с точки зрения времени выполнения и используемой памяти в зависимости от размера входных данных." ] }, en: { easy: [ "Hello world! This is a simple text for learning touch typing.", "The cat sits on the table. The dog runs in the yard.", "Mom cooks dinner. Dad reads the newspaper.", "Children play in the yard. Birds sing in the garden.", "The book lies on the shelf. The pen stands in the glass." ], medium: [ "Modern technology develops at a rapid pace. Every day new inventions appear that change our lives.", "Programming is the art of creating software. It requires logical thinking and attention to detail.", "Education plays an important role in the development of society. Knowledge helps people adapt to a changing world.", "Nature is beautiful at any time of year. In spring flowers bloom, in summer grass turns green, in autumn leaves turn yellow, in winter snow falls.", "Friendship is one of the most valuable human relationships. True friends will always support you in difficult times." ], hard: [ "Quantum mechanics is a fundamental theory that describes the physical properties of nature at the atomic and subatomic levels. It is the basis for understanding the behavior of matter and energy at microscopic scales.", "Syntactic analysis of natural language is a complex task that requires a deep understanding of grammatical structures, semantic relationships, and contextual dependencies between words and phrases.", "Economic theory studies the processes of production, distribution, and consumption of goods and services under conditions of resource scarcity. It helps understand the mechanisms of market economy functioning.", "Philosophy of science explores the nature of scientific knowledge, methods of scientific cognition, and criteria of scientificity. It raises questions about what truth is, how we can achieve it, and what are the limits of human knowledge.", "Algorithmic complexity is an important concept in computer science that characterizes the efficiency of algorithms in terms of execution time and memory usage depending on the size of input data." ] } }; // Раскладки клавиатуры this.keyboardLayouts = { ru: [ ['ё', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '='], ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ'], ['ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э'], ['я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'] ], en: [ ['`', '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', ',', '.', '/'] ] }; // Уроки для простой тренировки с уровнями сложности this.trainingLessons = { ru: { easy: [ { title: "Верхний ряд - основы", description: "Изучаем клавиши верхнего ряда через простые комбинации", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ'], text: "йц ук ен гш щз хъ йц ук ен гш щз хъ йц ук ен гш щз хъ" }, { title: "Верхний ряд - слова", description: "Тренируем верхний ряд через короткие слова", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ'], text: "йцу кен гшщ зхъ йцу кен гшщ зхъ йцу кен гшщ зхъ" }, { title: "Средний ряд - основы", description: "Изучаем клавиши среднего ряда через комбинации", keys: ['ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э'], text: "фы ва пр ол дж эф ыва про лдж э" }, { title: "Средний ряд - слова", description: "Тренируем средний ряд через слова и фразы", keys: ['ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э'], text: "фыва про лдж э фыва про лдж э" }, { title: "Нижний ряд - основы", description: "Изучаем клавиши нижнего ряда через комбинации", keys: ['я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "яч см ит ьб ю. яч см ит ьб ю." }, { title: "Нижний ряд - слова", description: "Тренируем нижний ряд через слова", keys: ['я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "ячс мит ьбю. ячс мит ьбю." }, { title: "Цифры и символы", description: "Изучаем цифры и специальные символы", keys: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '='], text: "123 456 789 0-= 123 456 789 0-=" }, { title: "Переходы между рядами", description: "Тренируем переходы между разными рядами", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "йцу фыв ячс кен про мит гшщ лдж ьбю зхъ эф ." }, { title: "Простые слова", description: "Тренируем простые русские слова", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "кот дом лес мир друг книга стол стул окно дверь" }, { title: "Фразы и предложения", description: "Тренируем короткие фразы", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "Привет мир! Как дела? Хорошо учиться. Новый день." } ], medium: [ { title: "Быстрые комбинации", description: "Тренируем быстрые переходы между клавишами", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ'], text: "йцукенгшщзхъ йцукенгшщзхъ йцукенгшщзхъ йцукенгшщзхъ йцукенгшщзхъ" }, { title: "Средний ряд - скорость", description: "Увеличиваем скорость набора среднего ряда", keys: ['ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э'], text: "фывапролджэ фывапролджэ фывапролджэ фывапролджэ фывапролджэ" }, { title: "Нижний ряд - скорость", description: "Быстрый набор нижнего ряда", keys: ['я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "ячсмитьбю. ячсмитьбю. ячсмитьбю. ячсмитьбю. ячсмитьбю." }, { title: "Смешанные ряды", description: "Тренируем переходы между всеми рядами", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "йцу фыв ячс кен про мит гшщ лдж ьбю зхъ эф . йцу фыв ячс кен про мит гшщ лдж ьбю зхъ эф ." }, { title: "Сложные слова", description: "Тренируем сложные русские слова", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "программирование компьютер клавиатура скорость печати программирование компьютер клавиатура скорость печати" }, { title: "Предложения", description: "Тренируем полные предложения", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "Сегодня хорошая погода. Я изучаю слепую печать. Это очень полезный навык. Сегодня хорошая погода. Я изучаю слепую печать." }, { title: "Длинные фразы", description: "Тренируем длинные фразы с пунктуацией", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "В современном мире умение быстро печатать становится все более важным навыком для успешной работы и учебы." } ], hard: [ { title: "Экспресс-набор", description: "Максимальная скорость набора всех клавиш", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "йцукенгшщзхъфывапролджэячсмитьбю. йцукенгшщзхъфывапролджэячсмитьбю. йцукенгшщзхъфывапролджэячсмитьбю." }, { title: "Технические термины", description: "Тренируем техническую лексику", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "алгоритм программирование разработка интерфейс база данных алгоритм программирование разработка интерфейс база данных" }, { title: "Сложные фразы", description: "Длинные и сложные предложения", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "Современные технологии развиваются стремительными темпами. Каждый день появляются новые изобретения, которые кардинально меняют нашу жизнь и работу." }, { title: "Цифры и символы", description: "Сложные комбинации с цифрами и символами", keys: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ'], text: "123-456-7890 йцукенгшщзхъ 1й2ц3у4к5е6н7г8ш9щ0з 123-456-7890 йцукенгшщзхъ 1й2ц3у4к5е6н7г8ш9щ0з" }, { title: "Профессиональный текст", description: "Тренируем профессиональную лексику", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "Программирование требует точности и внимательности. Каждый символ важен для корректной работы программы. Ошибка в одном символе может привести к серьезным проблемам в работе всего приложения." }, { title: "Научные термины", description: "Сложная научная и техническая лексика", keys: ['й', 'ц', 'у', 'к', 'е', 'н', 'г', 'ш', 'щ', 'з', 'х', 'ъ', 'ф', 'ы', 'в', 'а', 'п', 'р', 'о', 'л', 'д', 'ж', 'э', 'я', 'ч', 'с', 'м', 'и', 'т', 'ь', 'б', 'ю', '.'], text: "Квантовая механика представляет собой фундаментальную теорию, описывающую физические свойства природы на атомном и субатомном уровнях." } ] }, en: { easy: [ { title: "Top Row - Basics", description: "Learn top row keys through simple combinations", keys: ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']'], text: "qw er ty ui op [] qw er ty ui op []" }, { title: "Top Row - Words", description: "Practice top row through short words", keys: ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']'], text: "qwert yuiop [] qwert yuiop []" }, { title: "Home Row - Basics", description: "Learn home row keys through combinations", keys: ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'"], text: "as df gh jk l; 'as df gh jk l; '" }, { title: "Home Row - Words", description: "Practice home row through words and phrases", keys: ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'"], text: "asdf ghjk l;' asdf ghjk l;'" }, { title: "Bottom Row - Basics", description: "Learn bottom row keys through combinations", keys: ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/'], text: "zx cv bn m,./ zx cv bn m,./" }, { title: "Bottom Row - Words", description: "Practice bottom row through words", keys: ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/'], text: "zxcv bnm,./ zxcv bnm,./" }, { title: "Numbers and Symbols", description: "Learn numbers and special symbols", keys: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '='], text: "123 456 789 0-= 123 456 789 0-=" }, { title: "Row Transitions", description: "Practice transitions between different rows", keys: ['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'], text: "qwe asd zxc rty fgh vbn uio jkl m,." }, { title: "Simple Words", description: "Practice simple English words", keys: ['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'], text: "cat dog sun moon tree book desk chair table window" }, { title: "Phrases and Sentences", description: "Practice short phrases", keys: ['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'], text: "Hello world! How are you? Good morning. Nice day." } ], medium: [ { title: "Fast Combinations", description: "Practice fast transitions between keys", keys: ['q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']'], text: "qwertyuiop[] qwertyuiop[] qwertyuiop[] qwertyuiop[] qwertyuiop[]" }, { title: "Home Row Speed", description: "Increase typing speed on home row", keys: ['a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', "'"], text: "asdfghjkl;' asdfghjkl;' asdfghjkl;' asdfghjkl;' asdfghjkl;'" }, { title: "Bottom Row Speed", description: "Fast typing on bottom row", keys: ['z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/'], text: "zxcvbnm,./ zxcvbnm,./ zxcvbnm,./ zxcvbnm,./ zxcvbnm,./" }, { title: "Mixed Rows", description: "Practice transitions between all rows", keys: ['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'], text: "qwe asd zxc rty fgh vbn uio jkl m,. qwe asd zxc rty fgh vbn uio jkl m,. qwe asd zxc" }, { title: "Complex Words", description: "Practice complex English words", keys: ['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'], text: "programming computer keyboard typing speed accuracy programming computer keyboard typing speed accuracy" }, { title: "Sentences", description: "Practice full sentences", keys: ['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'], text: "Today is a beautiful day. I am learning touch typing. This is a very useful skill. Today is a beautiful day. I am learning touch typing." }, { title: "Long Phrases", description: "Practice long phrases with punctuation", keys: ['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'], text: "In the modern world, the ability to type quickly has become an increasingly important skill for successful work and study." } ], hard: [ { title: "Express Typing", description: "Maximum typing speed for all keys", keys: ['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'], text: "qwertyuiopasdfghjklzxcvbnm qwertyuiopasdfghjklzxcvbnm qwertyuiopasdfghjklzxcvbnm" }, { title: "Technical Terms", description: "Practice technical vocabulary", keys: ['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'], text: "algorithm programming development interface database algorithm programming development interface database" }, { title: "Complex Phrases", description: "Long and complex sentences", keys: ['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'], text: "Modern technology develops at a rapid pace. Every day new inventions appear that fundamentally change our lives and work processes." }, { title: "Numbers and Symbols", description: "Complex combinations with numbers and symbols", keys: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p'], text: "123-456-7890 qwertyuiop 1q2w3e4r5t6y7u8i9o0p 123-456-7890 qwertyuiop 1q2w3e4r5t6y7u8i9o0p" }, { title: "Professional Text", description: "Practice professional vocabulary", keys: ['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'], text: "Programming requires precision and attention to detail. Every character matters for correct program operation. A single error in one character can lead to serious problems in the entire application's functionality." }, { title: "Scientific Terms", description: "Complex scientific and technical vocabulary", keys: ['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'], text: "Quantum mechanics represents a fundamental theory that describes the physical properties of nature at the atomic and subatomic levels." } ] } }; this.init(); this.loadTheme(); } toggleTheme() { this.isDarkTheme = !this.isDarkTheme; this.applyTheme(); this.saveTheme(); } applyTheme() { const body = document.body; const themeIcon = document.querySelector('.theme-icon'); if (this.isDarkTheme) { body.setAttribute('data-theme', 'dark'); themeIcon.textContent = '☀️'; } else { body.removeAttribute('data-theme'); themeIcon.textContent = '🌙'; } } saveTheme() { localStorage.setItem('typingTrainerTheme', this.isDarkTheme ? 'dark' : 'light'); } loadTheme() { const savedTheme = localStorage.getItem('typingTrainerTheme'); if (savedTheme === 'dark') { this.isDarkTheme = true; } else if (savedTheme === 'light') { this.isDarkTheme = false; } else { // Автоопределение темы по системным настройкам this.isDarkTheme = window.matchMedia('(prefers-color-scheme: dark)').matches; } this.applyTheme(); } init() { this.setupEventListeners(); this.generateKeyboard(); this.loadNewExercise(); } setupEventListeners() { // Переключение языка document.getElementById('lang-ru').addEventListener('click', () => this.switchLanguage('ru')); document.getElementById('lang-en').addEventListener('click', () => this.switchLanguage('en')); // Поле ввода const textInput = document.getElementById('text-input'); textInput.addEventListener('input', (e) => this.handleInput(e)); textInput.addEventListener('keydown', (e) => this.handleKeyDown(e)); // Кнопки управления document.getElementById('new-exercise').addEventListener('click', () => this.loadNewExercise()); document.getElementById('pause-btn').addEventListener('click', () => this.togglePause()); document.getElementById('reset-btn').addEventListener('click', () => this.reset()); // Уровни сложности document.querySelectorAll('.difficulty-btn').forEach(btn => { btn.addEventListener('click', (e) => this.setDifficulty(e.target.dataset.level)); }); // Режимы тренировки document.querySelectorAll('.mode-btn').forEach(btn => { btn.addEventListener('click', (e) => this.setMode(e.target.dataset.mode)); }); // Переключатель темы document.getElementById('theme-toggle').addEventListener('click', () => this.toggleTheme()); // Модальное окно результатов document.getElementById('modal-close').addEventListener('click', () => this.closeResultModal()); document.getElementById('modal-cancel').addEventListener('click', () => this.closeResultModal()); document.getElementById('modal-next').addEventListener('click', () => this.nextExercise()); // Закрытие модального окна по клику вне его области document.getElementById('result-modal').addEventListener('click', (e) => { if (e.target.id === 'result-modal') { this.closeResultModal(); } }); // Обработка нажатий клавиш на виртуальной клавиатуре document.addEventListener('keydown', (e) => this.handleVirtualKeyboard(e)); } switchLanguage(lang) { this.currentLanguage = lang; // Обновляем активную кнопку языка document.querySelectorAll('.lang-btn').forEach(btn => btn.classList.remove('active')); document.getElementById(`lang-${lang}`).classList.add('active'); // Генерируем новую клавиатуру this.generateKeyboard(); // Сбрасываем прогресс тренировки при смене языка if (this.mode === 'training') { this.currentLesson = 0; this.lessonProgress = 0; } // Загружаем новое упражнение this.loadNewExercise(); } setDifficulty(level) { this.difficulty = level; // Обновляем активную кнопку сложности document.querySelectorAll('.difficulty-btn').forEach(btn => btn.classList.remove('active')); document.querySelector(`[data-level="${level}"]`).classList.add('active'); // Сбрасываем прогресс тренировки при смене сложности if (this.mode === 'training') { this.currentLesson = 0; this.lessonProgress = 0; } // Загружаем новое упражнение this.loadNewExercise(); } setMode(mode) { this.mode = mode; // Обновляем активную кнопку режима document.querySelectorAll('.mode-btn').forEach(btn => btn.classList.remove('active')); document.querySelector(`[data-mode="${mode}"]`).classList.add('active'); // Показываем/скрываем панель тренировки const trainingPanel = document.getElementById('training-panel'); if (mode === 'training') { trainingPanel.style.display = 'block'; this.startTrainingMode(); } else { trainingPanel.style.display = 'none'; this.loadNewExercise(); } } startTrainingMode() { this.currentLesson = 0; this.lessonProgress = 0; this.loadTrainingLesson(); } loadTrainingLesson() { const lessons = this.trainingLessons[this.currentLanguage][this.difficulty]; const lesson = lessons[this.currentLesson]; if (!lesson) { this.completeAllLessons(); return; } // Обновляем информацию об уроке document.getElementById('lesson-title').textContent = lesson.title; document.getElementById('lesson-description').textContent = lesson.description; document.getElementById('current-lesson').textContent = `Урок ${this.currentLesson + 1}: ${lesson.title}`; // Отображаем клавиши для изучения this.displayKeysToPress(lesson.keys); // Устанавливаем текст для печати this.currentText = lesson.text; this.displayText(); // Сбрасываем состояние this.reset(); // Обновляем прогресс this.updateTrainingProgress(); } displayKeysToPress(keys) { const container = document.getElementById('keys-to-press'); container.innerHTML = ''; keys.forEach((key, index) => { const keyElement = document.createElement('div'); keyElement.className = 'key-to-press'; keyElement.textContent = key; keyElement.id = `training-key-${index}`; container.appendChild(keyElement); }); // Инициализируем прогресс клавиш this.updateTrainingKeysProgress(0); } updateTrainingProgress() { const totalLessons = this.trainingLessons[this.currentLanguage][this.difficulty].length; // Вычисляем прогресс на основе текущего урока и выполнения текста let lessonProgress = 0; if (this.mode === 'training' && this.currentText) { const currentText = this.currentText.replace(/\s+/g, ' ').trim(); const userText = this.userInput.replace(/\s+/g, ' ').trim(); lessonProgress = Math.min((userText.length / currentText.length), 1); } const progress = ((this.currentLesson + lessonProgress) / totalLessons) * 100; document.getElementById('progress-fill').style.width = `${progress}%`; document.getElementById('progress-percent').textContent = `${Math.round(progress)}%`; } getCurrentLessonKeys() { const lessons = this.trainingLessons[this.currentLanguage][this.difficulty]; return lessons[this.currentLesson] ? lessons[this.currentLesson].keys : []; } completeAllLessons() { alert('Поздравляем! Вы завершили все уроки простой тренировки! Теперь вы можете перейти к обычной практике.'); this.setMode('practice'); } generateKeyboard() { const keyboard = document.getElementById('keyboard'); keyboard.innerHTML = ''; const layout = this.keyboardLayouts[this.currentLanguage]; layout.forEach((row, rowIndex) => { const rowDiv = document.createElement('div'); rowDiv.className = 'keyboard-row'; row.forEach(key => { const keyDiv = document.createElement('div'); keyDiv.className = 'key'; keyDiv.textContent = key; keyDiv.dataset.key = key; rowDiv.appendChild(keyDiv); }); keyboard.appendChild(rowDiv); }); } loadNewExercise() { if (this.mode === 'training') { this.loadTrainingLesson(); return; } const texts = this.texts[this.currentLanguage][this.difficulty]; this.currentText = texts[Math.floor(Math.random() * texts.length)]; // Отображаем текст this.displayText(); // Сбрасываем состояние this.reset(); } displayText() { const textElement = document.getElementById('text-to-type'); textElement.innerHTML = ''; for (let i = 0; i < this.currentText.length; i++) { const span = document.createElement('span'); span.textContent = this.currentText[i]; span.id = `char-${i}`; textElement.appendChild(span); } // Подсвечиваем первый символ this.highlightCurrentChar(); } highlightCurrentChar() { // Убираем подсветку со всех символов document.querySelectorAll('#text-to-type span').forEach(span => { span.classList.remove('current', 'correct', 'incorrect'); }); // Подсвечиваем текущий символ if (this.currentPosition < this.currentText.length) { const currentChar = document.getElementById(`char-${this.currentPosition}`); if (currentChar) { currentChar.classList.add('current'); } } } handleInput(e) { if (this.isPaused) return; this.userInput = e.target.value; if (!this.isTyping) { this.startTyping(); } this.updateProgress(); this.updateStats(); } handleKeyDown(e) { if (this.isPaused) return; // Обрабатываем специальные клавиши if (e.key === 'Backspace') { this.handleBackspace(); } else if (e.key === 'Enter' && this.isComplete()) { this.completeExercise(); } // Обновляем виртуальную клавиатуру this.updateVirtualKeyboard(e.key); } handleBackspace() { if (this.currentPosition > 0) { this.currentPosition--; this.highlightCurrentChar(); } } startTyping() { this.isTyping = true; this.startTime = Date.now(); this.startTimer(); } startTimer() { this.timerInterval = setInterval(() => { if (!this.isPaused && this.isTyping) { this.updateTimer(); } }, 1000); } updateTimer() { const elapsed = Math.floor((Date.now() - this.startTime) / 1000); const minutes = Math.floor(elapsed / 60); const seconds = elapsed % 60; document.getElementById('timer').textContent = `${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`; } updateProgress() { let correctChars = 0; let newErrors = 0; for (let i = 0; i < this.userInput.length && i < this.currentText.length; i++) { const userChar = this.userInput[i]; const correctChar = this.currentText[i]; const charElement = document.getElementById(`char-${i}`); if (userChar === correctChar) { charElement.classList.remove('incorrect'); charElement.classList.add('correct'); correctChars++; } else { charElement.classList.remove('correct'); charElement.classList.add('incorrect'); newErrors++; } } this.currentPosition = this.userInput.length; this.errors = newErrors; this.highlightCurrentChar(); // Обновляем прогресс тренировки if (this.mode === 'training') { this.updateTrainingProgress(); this.checkTrainingProgress(); } } checkTrainingProgress() { if (this.mode !== 'training') return; // Для режима тренировки проверяем прогресс по тексту, а не по отдельным клавишам const currentText = this.currentText.replace(/\s+/g, ' ').trim(); const userText = this.userInput.replace(/\s+/g, ' ').trim(); // Вычисляем процент выполнения const progress = Math.min((userText.length / currentText.length) * 100, 100); // Обновляем визуальный прогресс клавиш this.updateTrainingKeysProgress(progress); // Проверяем ошибки в режиме тренировки if (this.errors > this.maxErrors) { this.failCurrentLesson(); return; } // Проверяем завершение урока if (userText === currentText && !this.lessonFailed) { this.completeCurrentLesson(); } } updateTrainingKeysProgress(progress) { const currentKeys = this.getCurrentLessonKeys(); const keysToHighlight = Math.floor((progress / 100) * currentKeys.length); // Подсвечиваем пройденные клавиши for (let i = 0; i < currentKeys.length; i++) { const keyElement = document.getElementById(`training-key-${i}`); if (keyElement) { keyElement.classList.remove('current', 'completed', 'incorrect'); if (i < keysToHighlight) { keyElement.classList.add('completed'); } else if (i === keysToHighlight) { keyElement.classList.add('current'); } } } } failCurrentLesson() { if (this.lessonFailed) return; // Предотвращаем повторные вызовы this.lessonFailed = true; this.isTyping = false; // Останавливаем таймер if (this.timerInterval) { clearInterval(this.timerInterval); } const lesson = this.trainingLessons[this.currentLanguage][this.difficulty][this.currentLesson]; const userChoice = confirm( `Урок "${lesson.title}" провален!\n\n` + `Количество ошибок: ${this.errors} (максимум: ${this.maxErrors})\n\n` + `Хотите повторить урок?` ); if (userChoice) { // Повторяем урок this.retryCurrentLesson(); } else { // Переходим к следующему уроку this.currentLesson++; this.lessonProgress = 0; this.lessonFailed = false; if (this.currentLesson < this.trainingLessons[this.currentLanguage][this.difficulty].length) { this.loadTrainingLesson(); } else { this.completeAllLessons(); } } } retryCurrentLesson() { this.lessonFailed = false; this.lessonProgress = 0; this.loadTrainingLesson(); } completeCurrentLesson() { // Показываем сообщение о завершении урока const lesson = this.trainingLessons[this.currentLanguage][this.difficulty][this.currentLesson]; alert(`Отлично! Урок "${lesson.title}" завершен!`); // Переходим к следующему уроку this.currentLesson++; this.lessonProgress = 0; this.lessonFailed = false; if (this.currentLesson < this.trainingLessons[this.currentLanguage][this.difficulty].length) { this.loadTrainingLesson(); } else { this.completeAllLessons(); } } updateStats() { const timeElapsed = (Date.now() - this.startTime) / 1000 / 60; // в минутах const wpm = timeElapsed > 0 ? Math.round(this.userInput.length / 5 / timeElapsed) : 0; const accuracy = this.userInput.length > 0 ? Math.round(((this.userInput.length - this.errors) / this.userInput.length) * 100) : 100; document.getElementById('wpm').textContent = wpm; document.getElementById('accuracy').textContent = accuracy; document.getElementById('errors').textContent = this.errors; // Обновляем предупреждение об ошибках в режиме тренировки if (this.mode === 'training') { this.updateErrorWarning(); } } updateErrorWarning() { const errorWarning = document.getElementById('error-warning'); const errorCount = document.getElementById('error-count'); const maxErrors = document.getElementById('max-errors'); if (this.errors > 0) { errorWarning.style.display = 'block'; errorCount.textContent = this.errors; maxErrors.textContent = this.maxErrors; // Меняем цвет в зависимости от количества ошибок if (this.errors >= this.maxErrors) { errorWarning.style.background = '#f8d7da'; errorWarning.style.borderColor = '#dc3545'; errorWarning.style.color = '#721c24'; } else if (this.errors >= this.maxErrors - 1) { errorWarning.style.background = '#fff3cd'; errorWarning.style.borderColor = '#ffc107'; errorWarning.style.color = '#856404'; } } else { errorWarning.style.display = 'none'; } } updateVirtualKeyboard(key) { // Убираем активность со всех клавиш document.querySelectorAll('.key').forEach(keyEl => { keyEl.classList.remove('active', 'incorrect'); }); // Находим и подсвечиваем нажатую клавишу const keyElement = document.querySelector(`[data-key="${key}"]`); if (keyElement) { keyElement.classList.add('active'); // Проверяем правильность нажатия if (this.currentPosition < this.currentText.length) { const correctChar = this.currentText[this.currentPosition]; if (key !== correctChar) { keyElement.classList.add('incorrect'); } } // Убираем подсветку через короткое время setTimeout(() => { keyElement.classList.remove('active'); }, 200); } } isComplete() { return this.userInput === this.currentText; } completeExercise() { this.isTyping = false; clearInterval(this.timerInterval); // Вычисляем статистику const timeElapsed = (Date.now() - this.startTime) / 1000 / 60; const wpm = Math.round(this.userInput.length / 5 / timeElapsed); const accuracy = Math.round(((this.userInput.length - this.errors) / this.userInput.length) * 100); const timeInSeconds = Math.floor(timeElapsed * 60); // Разные сообщения для разных режимов if (this.mode === 'training') { alert(`Упражнение завершено!\nСкорость: ${wpm} зн/мин\nТочность: ${accuracy}%\nОшибки: ${this.errors}`); // Загружаем новое упражнение в режиме тренировки setTimeout(() => this.loadNewExercise(), 1000); } else { // Для обычной практики показываем красивое модальное окно this.showResultModal(wpm, accuracy, this.errors, timeInSeconds); } } showResultModal(wpm, accuracy, errors, timeInSeconds) { // Заполняем данные в модальном окне document.getElementById('result-wpm').textContent = wpm; document.getElementById('result-accuracy').textContent = accuracy; document.getElementById('result-errors').textContent = errors; document.getElementById('result-time').textContent = timeInSeconds; // Показываем модальное окно document.getElementById('result-modal').style.display = 'flex'; } closeResultModal() { document.getElementById('result-modal').style.display = 'none'; } nextExercise() { this.closeResultModal(); this.loadNewExercise(); } togglePause() { this.isPaused = !this.isPaused; const pauseBtn = document.getElementById('pause-btn'); if (this.isPaused) { pauseBtn.textContent = 'Продолжить'; pauseBtn.classList.add('paused'); } else { pauseBtn.textContent = 'Пауза'; pauseBtn.classList.remove('paused'); } } reset() { this.userInput = ''; this.currentPosition = 0; this.errors = 0; this.isTyping = false; this.isPaused = false; this.lessonFailed = false; // Очищаем поле ввода document.getElementById('text-input').value = ''; // Сбрасываем статистику document.getElementById('wpm').textContent = '0'; document.getElementById('accuracy').textContent = '100'; document.getElementById('timer').textContent = '00:00'; document.getElementById('errors').textContent = '0'; // Сбрасываем кнопку паузы const pauseBtn = document.getElementById('pause-btn'); pauseBtn.textContent = 'Пауза'; pauseBtn.classList.remove('paused'); // Очищаем таймер if (this.timerInterval) { clearInterval(this.timerInterval); } // Обновляем отображение текста this.displayText(); // Убираем активность с клавиатуры document.querySelectorAll('.key').forEach(keyEl => { keyEl.classList.remove('active', 'incorrect'); }); // Скрываем предупреждение об ошибках const errorWarning = document.getElementById('error-warning'); if (errorWarning) { errorWarning.style.display = 'none'; } } } // Инициализация тренажера document.addEventListener('DOMContentLoaded', () => { new TypingTrainer(); });