Files
2026-etpgrf-site/public/static/js/index.js

100 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Импортируем из локального бандла (относительный путь)
import {
EditorView,
EditorState,
lineNumbers,
highlightActiveLineGutter,
highlightWhitespace,
highlightTrailingWhitespace,
drawSelection,
keymap,
highlightSpecialChars,
html,
oneDark,
syntaxHighlighting,
defaultHighlightStyle,
bracketMatching,
defaultKeymap,
Compartment
} from "../codemirror/editor.js";
const resultWrapper = document.getElementById('cm-result-wrapper');
const themeCompartment = new Compartment();
function getTheme() {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? oneDark : [];
}
// Словарь названий для спецсимволов
const charNames = {
0x00A0: "NoBreakable Space (неразрывный пробел —  )",
0x00AD: "Soft Hyphen (мягкий перенос — ­)",
0x2002: "En Space (полужирный пробел —  )",
0x2003: "Em Space (жирный пробел —  )",
0x2007: "Figure Space (цифровой пробел —  )",
0x2008: "Punctuation Space (пунктуационный пробел —  )",
0x2009: "Thin Space (тонкий пробел —  )",
0x200A: "Hair Space (толщина волоса —  )",
0x200B: "Negative Space (негативный пробел — ​)",
0x200C: "Zero Width Non-Joiner (пробел нулевой ширины, без объединения — ‍)",
0x200D: "Zero Width Joiner (пробел нулевой ширины, с объединением — ‌)",
0x200E: "Left-to-Right Mark (изменить направление текста на слева-направо — ‎)",
0x200F: "Right-to-Left Mark (изменить направление текста на справа-налево — ‏)",
0x205F: "Medium Mathematical Space (средний пробел —  )",
0x2060: "NoBreak (без разрыва — ⁠)",
0x2062: "Invisible Times (невидимое умножение для семантической разметки математических выражений — ⁢)",
0x2063: "Invisible Comma (невидимая запятая для семантической разметки математических выражений — ⁣)",
};
const resultState = EditorState.create({
doc: "Здесь появится результат...",
extensions: [
lineNumbers(),
highlightActiveLineGutter(),
// Подсветка NBSP и других специальных пробелов
highlightSpecialChars({
specialChars: /[\u2002\u00AD\u2003\u2007\u2009\u00a0\u200A\u200B\u200C\u200D\u200E\u200F\u205F\u2060\u2062\u2063]/,
addSpecialChars: true,
render: (code) => {
let span = document.createElement("span");
span.textContent = "•";
span.style.background = "#ff000044"; // Полупрозрачный красный фон
span.style.color = "#ffff00"; // Желтый цвет точки
// Используем словарь для title
span.title = "U+" + code.toString(16).toUpperCase().padStart(4, '0') + " / " + (charNames[code] || "Special Char");
return span;
}
}),
highlightWhitespace(),
highlightTrailingWhitespace(),
drawSelection(),
syntaxHighlighting(defaultHighlightStyle, {fallback: true}),
bracketMatching(),
keymap.of(defaultKeymap),
html(),
themeCompartment.of(getTheme()),
EditorState.readOnly.of(true)
]
});
const resultView = new EditorView({
state: resultState,
parent: resultWrapper
});
document.body.addEventListener('htmx:afterSwap', function (evt) {
if (evt.detail.target.id === 'result-area') {
const newContent = evt.detail.xhr.response;
resultView.dispatch({
changes: {from: 0, to: resultView.state.doc.length, insert: newContent}
});
}
});
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
resultView.dispatch({
effects: themeCompartment.reconfigure(getTheme())
});
});