Ultima attività 2 weeks ago

"Микросервис для расстановки ударений в русском тексте. Выделите букву и нажмите Ctrl+Q.

KarelWintersky ha revisionato questo gist 2 weeks ago. Vai alla revisione

1 file changed, 298 insertions

accent_marker.html(file creato)

@@ -0,0 +1,298 @@
1 + <!DOCTYPE html>
2 + <html lang="ru">
3 + <head>
4 + <meta charset="UTF-8">
5 + <meta name="viewport" content="width=device-width, initial-scale=1.0">
6 + <title>Расстановка ударений</title>
7 + <meta name="description" content="Микросервис для расстановки ударений в русском тексте. Выделите букву и нажмите Ctrl+Q.">
8 + <meta name="keywords" content="ударения, русский язык, текст, форматирование, ударные гласные">
9 + <meta name="author" content="ООО Психотроника">
10 + <meta name="copyright" content="ООО Психотроника, 2026">
11 + <meta name="robots" content="index, follow">
12 + <style>
13 + * {
14 + margin: 0;
15 + padding: 0;
16 + box-sizing: border-box;
17 + }
18 +
19 + body {
20 + font-family: Arial, sans-serif;
21 + line-height: 1.6;
22 + padding: 20px;
23 + background-color: #f5f5f5;
24 + }
25 +
26 + .container {
27 + max-width: 800px;
28 + margin: 0 auto;
29 + background: white;
30 + padding: 20px;
31 + border-radius: 8px;
32 + box-shadow: 0 2px 10px rgba(0,0,0,0.1);
33 + }
34 +
35 + h1 {
36 + color: #333;
37 + margin-bottom: 10px;
38 + text-align: center;
39 + }
40 +
41 + .description {
42 + color: #666;
43 + margin-bottom: 20px;
44 + text-align: center;
45 + font-size: 14px;
46 + }
47 +
48 + textarea {
49 + width: 100%;
50 + min-height: 300px;
51 + padding: 15px;
52 + font-size: 16px;
53 + line-height: 1.5;
54 + border: 2px solid #ddd;
55 + border-radius: 4px;
56 + resize: vertical;
57 + font-family: inherit;
58 + margin-bottom: 15px;
59 + }
60 +
61 + textarea:focus {
62 + outline: none;
63 + border-color: #4CAF50;
64 + }
65 +
66 + .controls {
67 + display: flex;
68 + justify-content: space-between;
69 + align-items: center;
70 + margin-bottom: 20px;
71 + padding: 15px;
72 + background: #f8f9fa;
73 + border-radius: 4px;
74 + }
75 +
76 + .hotkey-info {
77 + font-size: 14px;
78 + color: #666;
79 + }
80 +
81 + .hotkey-info kbd {
82 + background: #e9ecef;
83 + padding: 2px 6px;
84 + border-radius: 3px;
85 + border: 1px solid #ced4da;
86 + font-family: monospace;
87 + }
88 +
89 + .examples {
90 + background: #f8f9fa;
91 + padding: 15px;
92 + border-radius: 4px;
93 + margin-top: 20px;
94 + font-size: 14px;
95 + }
96 +
97 + .examples h3 {
98 + margin-bottom: 10px;
99 + color: #333;
100 + }
101 +
102 + .example-item {
103 + margin-bottom: 5px;
104 + color: #666;
105 + }
106 +
107 + .copyright {
108 + text-align: center;
109 + margin-top: 20px;
110 + padding: 10px;
111 + color: #666;
112 + font-size: 12px;
113 + border-top: 1px solid #eee;
114 + }
115 +
116 + footer {
117 + text-align: center;
118 + margin-top: 20px;
119 + color: #888;
120 + font-size: 12px;
121 + }
122 + </style>
123 + </head>
124 + <body>
125 + <div class="container">
126 + <h1>Добавление ударений в текст</h1>
127 + <div class="description">
128 + Выделите букву и нажмите Ctrl+Q (Cmd+Q на Mac), чтобы добавить ударение
129 + </div>
130 +
131 + <div class="controls">
132 + <div class="hotkey-info">
133 + Горячая клавиша: <kbd>Ctrl</kbd> + <kbd>Q</kbd> (Windows/Linux) или <kbd>Cmd</kbd> + <kbd>Q</kbd> (Mac)
134 + </div>
135 + </div>
136 +
137 + <textarea id="textInput" placeholder="Введите или вставьте ваш текст здесь..."></textarea>
138 +
139 + <div class="examples">
140 + <h3>Примеры замены:</h3>
141 + <div class="example-item">а → á (если это ударная "а")</div>
142 + <div class="example-item">о → ó (если это ударная "о")</div>
143 + <div class="example-item">у → у́ (во всех остальных случаях знак ударения ставится после буквы)</div>
144 + <div class="example-item">Выделите одну букву и нажмите Ctrl+Q</div>
145 + </div>
146 + </div>
147 +
148 + <footer>
149 + Микросервис для расстановки ударений
150 + <div class="copyright">
151 + &copy; ООО Психотроника, 2026.
152 + </div>
153 +
154 + </footer>
155 +
156 + <script>
157 +
158 + // Правила замены для ударных гласных
159 + const stressRules = {
160 + 'а': 'á',
161 + 'о': 'ó',
162 + 'е': 'é',
163 + 'у': 'у́',
164 + 'ы': 'ы́',
165 + 'э': 'э́',
166 + 'ю': 'ю́',
167 + 'я': 'я́',
168 + 'и': 'и́',
169 + 'А': 'Á',
170 + 'О': 'Ó',
171 + 'Е': 'É',
172 + 'У': 'У́',
173 + 'Ы': 'Ы́',
174 + 'Э': 'Э́',
175 + 'Ю': 'Ю́',
176 + 'Я': 'Я́',
177 + 'И': 'И́'
178 + };
179 +
180 + // Обратная замена для удаления ударений
181 + const reverseStressRules = {
182 + 'á': 'а', 'Á': 'А',
183 + 'ó': 'о', 'Ó': 'О',
184 + 'é': 'е', 'É': 'Е',
185 + 'у́': 'у', 'У́': 'У',
186 + 'ы́': 'ы', 'Ы́': 'Ы',
187 + 'э́': 'э', 'Э́': 'Э',
188 + 'ю́': 'ю', 'Ю́': 'Ю',
189 + 'я́': 'я', 'Я́': 'Я',
190 + 'и́': 'и', 'И́': 'И'
191 + };
192 +
193 + // Получаем текстовое поле
194 + const textInput = document.getElementById('textInput');
195 +
196 + // Функция для проверки, заканчивается ли текст на ударение
197 + function endsWithStress(text) {
198 + // Проверяем последний символ на наличие ударения (комбинирующий символ ́)
199 + if (text.length === 0) return false;
200 +
201 + // Если последний символ - комбинирующее ударение (U+0301)
202 + if (text.charCodeAt(text.length - 1) === 0x0301) {
203 + return true;
204 + }
205 +
206 + // Проверяем комбинированные символы (ударение как часть символа)
207 + const lastChar = text.charAt(text.length - 1);
208 + return reverseStressRules.hasOwnProperty(lastChar);
209 + }
210 +
211 + // Функция для удаления ударения
212 + function removeStress(text) {
213 + if (text.length === 0) return text;
214 +
215 + // Если последний символ - комбинирующее ударение
216 + if (text.charCodeAt(text.length - 1) === 0x0301) {
217 + return text.slice(0, -1);
218 + }
219 +
220 + // Если последний символ имеет предварительно составленное ударение
221 + const lastChar = text.charAt(text.length - 1);
222 + if (reverseStressRules[lastChar]) {
223 + return text.slice(0, -1) + reverseStressRules[lastChar];
224 + }
225 +
226 + return text;
227 + }
228 +
229 + // Обработка нажатия клавиш
230 + textInput.addEventListener('keydown', function(e) {
231 + // Проверяем комбинацию Ctrl+Q/Й или Cmd+Q/Й
232 + if ((e.ctrlKey || e.metaKey) && (e.key === 'q' || e.key === 'й' || e.key === 'Й' || e.key === 'Q')) {
233 + e.preventDefault();
234 +
235 + const start = this.selectionStart;
236 + const end = this.selectionEnd;
237 +
238 + // Если нет выделения или выделен 0 символов
239 + if (start === end) {
240 + alert('Пожалуйста, выделите хотя бы одну букву');
241 + return;
242 + }
243 +
244 + const selectedText = this.value.substring(start, end);
245 +
246 + // Проверяем, что есть хотя бы одна русская буква в выделении
247 + if (!/[а-яА-ЯёЁ]/.test(selectedText)) {
248 + alert('Выделите хотя бы одну русскую букву');
249 + return;
250 + }
251 +
252 + // ПРОВЕРКА: если текст заканчивается на ударение - удаляем его
253 + if (endsWithStress(selectedText)) {
254 + const textWithoutStress = removeStress(selectedText);
255 + const newText = this.value.substring(0, start) + textWithoutStress + this.value.substring(end);
256 + this.value = newText;
257 + this.selectionStart = start + textWithoutStress.length;
258 + this.selectionEnd = start + textWithoutStress.length;
259 + }
260 + // ДОБАВЛЕНИЕ ударения
261 + else {
262 + // Если выделена одна буква - применяем правила замены
263 + if (selectedText.length === 1) {
264 + let replacement;
265 + if (stressRules[selectedText]) {
266 + replacement = stressRules[selectedText];
267 + } else {
268 + replacement = selectedText + '́';
269 + }
270 +
271 + // Заменяем выделенный текст
272 + const newText = this.value.substring(0, start) + replacement + this.value.substring(end);
273 + this.value = newText;
274 + this.selectionStart = start + replacement.length;
275 + this.selectionEnd = start + replacement.length;
276 + }
277 + // Если выделено несколько символов - ставим ударение после выделения
278 + else {
279 + const replacement = selectedText + '́';
280 + const newText = this.value.substring(0, start) + replacement + this.value.substring(end);
281 + this.value = newText;
282 + this.selectionStart = start + replacement.length;
283 + this.selectionEnd = start + replacement.length;
284 + }
285 + }
286 +
287 + this.focus();
288 + }
289 + });
290 +
291 + // Фокус на текстовом поле при загрузке
292 + window.addEventListener('load', function() {
293 + textInput.focus();
294 + });
295 +
296 + </script>
297 + </body>
298 + </html>
Più nuovi Più vecchi