From 0e62d5ca8d387162f85024201e0b448fbaa71ff4 Mon Sep 17 00:00:00 2001 From: Vladislav Kopnin Date: Tue, 22 Sep 2026 15:32:43 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A4=D1=80=D0=BE=D0=BD=D1=82:=20=D1=82=D0=BE?= =?UTF-8?q?=D1=87=D0=BA=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BD=D0=BE=D1=81?= =?UTF-8?q?=D0=B0=20=D0=B2=20=D0=B4=D0=BB=D0=B8=D0=BD=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D1=81=D1=81=D1=8B=D0=BB=D0=BA=D0=B0=D1=85=20(),=20=D0=BD?= =?UTF-8?q?=D0=B5=20=D0=BF=D0=BE=D0=BB=D0=B0=D0=B3=D0=B0=D0=B5=D0=BC=D1=81?= =?UTF-8?q?=D1=8F=20=D0=BD=D0=B0=20CSS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ссылка на онлайн-курс в поле аудитории — одно длинное слово. CSS-фикс (overflow-wrap/word-break) работает в современных движках, но на телефоне пользователя переполнение оставалось: старый движок или закэшированный CSS. Теперь фронтенд сам расставляет : после служебных символов ссылок (/, ?, &, =, ., _, -) и не реже, чем каждые 24 символа; экранирование сохраняется. Перенос работает в любом браузере. Проверено в headless Chromium (390px и 320px): переполнений нет как с включёнными CSS-переносами, так и с принудительно отключёнными (эмуляция старого движка). --- README.md | 3 +++ src/frontend/static/app.js | 26 ++++++++++++++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 6c06888..ea32b4c 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,9 @@ nginx (https://schedule.our-place.ru) → 127.0.0.1:8090 заменяется на «Окно». - Подпись недели появляется только там, где недели действительно различаются; бейдж «Сейчас» подсвечивает текущую неделю. +- Длинные ссылки в карточке переносятся по служебным символам и каждые + 24 символа (``), поэтому карточка не вылезает за экран даже в старых + браузерах, где нет `overflow-wrap`. - Приложение можно «установить» на главный экран (манифест + service worker + иконки приложения); на iOS иконку берёт `apple-touch-icon`. diff --git a/src/frontend/static/app.js b/src/frontend/static/app.js index 215e903..b7d5ef2 100644 --- a/src/frontend/static/app.js +++ b/src/frontend/static/app.js @@ -239,10 +239,10 @@ function entityLessonHTML(parity, entry) {
${badge} ${entry.marker ? `${escapeHTML(entry.marker)}` : ""} - ${escapeHTML(entry.subject)} + ${withBreaks(entry.subject)}
- ${details.length ? `
${escapeHTML(details.join(" · "))}
` : ""} - ${entry.note ? `
${escapeHTML(entry.note)}
` : ""} + ${details.length ? `
${withBreaks(details.join(" · "))}
` : ""} + ${entry.note ? `
${withBreaks(entry.note)}
` : ""} `; } @@ -277,10 +277,10 @@ function singleLessonHTML(badgeKey, lesson, full) {
${badge} ${lesson.marker ? `${escapeHTML(lesson.marker)}` : ""} - ${escapeHTML(lesson.subject)} + ${withBreaks(lesson.subject)}
- ${details ? `
${escapeHTML(details)}
` : ""} - ${lesson.note ? `
${escapeHTML(lesson.note)}
` : ""} + ${details ? `
${withBreaks(details)}
` : ""} + ${lesson.note ? `
${withBreaks(lesson.note)}
` : ""} `; } @@ -490,6 +490,20 @@ function escapeHTML(s) { return s.replace(/[&<>"']/g, (c) => ({ "&": "&", "<": "<", ">": ">", '"': """, "'": "'" }[c])); } +/** + * Экранирует текст и расставляет точки переноса . + * Длинные ссылки (и вообще слова без пробелов) переносятся в любом браузере — + * не полагаемся на поддержку overflow-wrap: anywhere старыми движками. + */ +function withBreaks(text) { + const WBR = "\u0001"; // служебный маркер, в тексте таблицы не встречается + if (!text) return ""; + const marked = String(text) + .replace(/([/?&=._\-])(?=\S)/g, "$1" + WBR) // после служебных символов ссылок + .replace(/(\S{24})(?=\S)/g, "$1" + WBR); // и не реже, чем каждые 24 символа + return escapeHTML(marked).split(WBR).join(""); +} + function applyTheme(theme) { document.documentElement.setAttribute("data-theme", theme); localStorage.setItem("theme", theme);