fix: настройки типографа (17) подсветка пробелов работает
This commit is contained in:
@@ -21,7 +21,7 @@
|
|||||||
<div class="row">
|
<div class="row">
|
||||||
{# КОЛОНКА 1 #}<div class="col-md-4">
|
{# КОЛОНКА 1 #}<div class="col-md-4">
|
||||||
{# Выбор языка (Alpine.js) #}<div class="mb-3"
|
{# Выбор языка (Alpine.js) #}<div class="mb-3"
|
||||||
x-data="{ desc: 'Только русская типографика: кавычки «ёлочки» („вложенные“); длинное тире (—) с пробелами; «прилипающие» союзы и предлоги только для русского языка, переносы слов и т. д.' }">
|
x-data="{ desc: 'Только русская типографика: кавычки «ёлочки» („вложенные“); длинное тире (—) с пробелами; «прилипающие» союзы и предлоги только для русского языка, переносы слов и т. д.' }">
|
||||||
<div class="d-flex align-items-center mb-1">
|
<div class="d-flex align-items-center mb-1">
|
||||||
{# Иконка вместо чекбокса #}<div class="me-2 text-center" style="width: 1.25em;">
|
{# Иконка вместо чекбокса #}<div class="me-2 text-center" style="width: 1.25em;">
|
||||||
<i class="bi bi-globe"></i>
|
<i class="bi bi-globe"></i>
|
||||||
@@ -30,7 +30,7 @@
|
|||||||
<select class="form-select form-select-sm w-auto" name="langs"
|
<select class="form-select form-select-sm w-auto" name="langs"
|
||||||
@change="desc = $event.target.options[$event.target.selectedIndex].dataset.desc">
|
@change="desc = $event.target.options[$event.target.selectedIndex].dataset.desc">
|
||||||
<option value="ru" selected
|
<option value="ru" selected
|
||||||
data-desc="Только русская типографика: кавычки «ёлочки» („вложенные“); длинное тире (—) с пробелами; «прилипающие» союзы и предлоги только для русского языка, переносы слов и т. д.">
|
data-desc="Только русская типографика: кавычки «ёлочки» („вложенные“); длинное тире (—) с пробелами; «прилипающие» союзы и предлоги только для русского языка, переносы слов и т. д.">
|
||||||
Русский
|
Русский
|
||||||
</option>
|
</option>
|
||||||
<option value="en"
|
<option value="en"
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
<label class="form-check-label fw-bold" for="optQuotes">Обработка кавычек</label>
|
<label class="form-check-label fw-bold" for="optQuotes">Обработка кавычек</label>
|
||||||
</div>
|
</div>
|
||||||
{# Описание (видно, когда выключено) #}<div class="ms-3 form-text text-muted small" x-show="!enabled" x-transition>
|
{# Описание (видно, когда выключено) #}<div class="ms-3 form-text text-muted small" x-show="!enabled" x-transition>
|
||||||
Прямые кавычки (") не будут заменяться на типографские («…ёлочки…» или “…лапки…”).
|
Прямые кавычки (") не будут заменяться на типографские («…ёлочки…» или “…лапки…”).
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{# ========== #}<hr class="my-2" />
|
{# ========== #}<hr class="my-2" />
|
||||||
@@ -92,7 +92,7 @@
|
|||||||
<label class="form-check-label fw-bold" for="optUnbreakables">Неразрывные пробелы</label>
|
<label class="form-check-label fw-bold" for="optUnbreakables">Неразрывные пробелы</label>
|
||||||
</div>
|
</div>
|
||||||
{# Описание группы "Неразрывные пробелы" (видно, когда выключено) #}<div class="ms-3 form-text text-muted small" x-show="!enabled" x-transition>
|
{# Описание группы "Неразрывные пробелы" (видно, когда выключено) #}<div class="ms-3 form-text text-muted small" x-show="!enabled" x-transition>
|
||||||
Если отключено, то предлоги, союзы и артикли могут оставаться в конце строки, частицы (<em>бы, же…</em>) могут отрываться от слов.
|
Если отключено, то предлоги, союзы и артикли могут оставаться в конце строки, частицы (<em>бы, же…</em>) могут отрываться от слов.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{# ========== #}<hr class="my-2" />
|
{# ========== #}<hr class="my-2" />
|
||||||
@@ -156,7 +156,7 @@
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
{# Описание группы "Санитайзер" (видно, когда выключено) #}<div class="ms-3 form-text text-muted small" x-show="!enabled" x-transition>
|
{# Описание группы "Санитайзер" (видно, когда выключено) #}<div class="ms-3 form-text text-muted small" x-show="!enabled" x-transition>
|
||||||
Текст будет обработан «как есть», без предварительной очистки от HTML-тегов или старой разметки.
|
Текст будет обработан «как есть», без предварительной очистки от HTML-тегов или старой разметки.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{# ========== #}<hr class="my-2" />
|
{# ========== #}<hr class="my-2" />
|
||||||
@@ -203,54 +203,24 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
// Используем esm.sh с фиксированной версией для всех пакетов, чтобы избежать дублирования зависимостей
|
// Используем esm.sh с фиксированной версией для всех пакетов
|
||||||
import {EditorView, minimalSetup} from "https://esm.sh/codemirror@6.0.1?deps=@codemirror/state@6.2.1";
|
import {EditorView, lineNumbers, highlightActiveLineGutter, highlightWhitespace, highlightTrailingWhitespace, drawSelection, keymap} from "https://esm.sh/@codemirror/view@6.17.1?deps=@codemirror/state@6.2.1";
|
||||||
import {lineNumbers, highlightActiveLineGutter, ViewPlugin, Decoration} from "https://esm.sh/@codemirror/view@6.17.1?deps=@codemirror/state@6.2.1";
|
|
||||||
import {html} from "https://esm.sh/@codemirror/lang-html@6.4.5?deps=@codemirror/state@6.2.1";
|
import {html} from "https://esm.sh/@codemirror/lang-html@6.4.5?deps=@codemirror/state@6.2.1";
|
||||||
import {oneDark} from "https://esm.sh/@codemirror/theme-one-dark@6.1.2?deps=@codemirror/state@6.2.1";
|
import {oneDark} from "https://esm.sh/@codemirror/theme-one-dark@6.1.2?deps=@codemirror/state@6.2.1";
|
||||||
import {EditorState} from "https://esm.sh/@codemirror/state@6.2.1";
|
import {EditorState} from "https://esm.sh/@codemirror/state@6.2.1";
|
||||||
|
import {defaultKeymap} from "https://esm.sh/@codemirror/commands@6.2.4?deps=@codemirror/state@6.2.1";
|
||||||
|
|
||||||
const resultWrapper = document.getElementById('cm-result-wrapper');
|
const resultWrapper = document.getElementById('cm-result-wrapper');
|
||||||
|
|
||||||
// Декоратор для подсветки NBSP
|
|
||||||
const nbspDecoration = Decoration.mark({
|
|
||||||
attributes: {
|
|
||||||
style: "background-color: rgba(108, 117, 125, 0.2); border-radius: 2px;"
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const nbspScanner = ViewPlugin.fromClass(class {
|
|
||||||
constructor(view) {
|
|
||||||
this.decorations = this.getDecorations(view);
|
|
||||||
}
|
|
||||||
update(update) {
|
|
||||||
if (update.docChanged || update.viewportChanged) {
|
|
||||||
this.decorations = this.getDecorations(update.view);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
getDecorations(view) {
|
|
||||||
const builder = new Decoration.Builder();
|
|
||||||
for (const {from, to} of view.visibleRanges) {
|
|
||||||
const text = view.state.doc.sliceString(from, to);
|
|
||||||
let match;
|
|
||||||
const nbspRegex = /\u00a0/g;
|
|
||||||
while (match = nbspRegex.exec(text)) {
|
|
||||||
builder.add(from + match.index, from + match.index + 1, nbspDecoration);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return builder.finish();
|
|
||||||
}
|
|
||||||
}, {
|
|
||||||
decorations: v => v.decorations
|
|
||||||
});
|
|
||||||
|
|
||||||
const resultState = EditorState.create({
|
const resultState = EditorState.create({
|
||||||
doc: "Здесь появится результат...",
|
doc: "Здесь появится результат...",
|
||||||
extensions: [
|
extensions: [
|
||||||
minimalSetup,
|
|
||||||
lineNumbers(),
|
lineNumbers(),
|
||||||
highlightActiveLineGutter(),
|
highlightActiveLineGutter(),
|
||||||
nbspScanner, // <-- Наш плагин
|
highlightWhitespace(), // Подсветка всех пробелов
|
||||||
|
highlightTrailingWhitespace(), // Подсветка пробелов в конце
|
||||||
|
drawSelection(),
|
||||||
|
keymap.of(defaultKeymap),
|
||||||
html(),
|
html(),
|
||||||
oneDark,
|
oneDark,
|
||||||
EditorState.readOnly.of(true)
|
EditorState.readOnly.of(true)
|
||||||
@@ -264,7 +234,6 @@
|
|||||||
|
|
||||||
document.body.addEventListener('htmx:afterSwap', function(evt) {
|
document.body.addEventListener('htmx:afterSwap', function(evt) {
|
||||||
if (evt.detail.target.id === 'result-area') {
|
if (evt.detail.target.id === 'result-area') {
|
||||||
// ИСПОЛЬЗУЕМ responseText, ЧТОБЫ ПОЛУЧИТЬ СЫРОЙ ОТВЕТ (С МНЕМОНИКАМИ)
|
|
||||||
const newContent = evt.detail.xhr.response;
|
const newContent = evt.detail.xhr.response;
|
||||||
resultView.dispatch({
|
resultView.dispatch({
|
||||||
changes: { from: 0, to: resultView.state.doc.length, insert: newContent }
|
changes: { from: 0, to: resultView.state.doc.length, insert: newContent }
|
||||||
|
|||||||
Reference in New Issue
Block a user