Добавлена обработка многострочного выделения для списков и цитат в компонентах NoteEditor и NoteItem. Улучшена логика добавления тегов в зависимости от формата выделенного текста, включая поддержку чекбоксов и нумерованных списков.

This commit is contained in:
Fovway 2025-11-04 12:39:14 +07:00
parent bdd932bbbb
commit e3b98ea8d3
2 changed files with 146 additions and 18 deletions

View File

@ -327,15 +327,79 @@ export const NoteEditor: React.FC<NoteEditorProps> = ({ onSave }) => {
newEnd = start + innerText.length; newEnd = start + innerText.length;
} }
} else { } else {
// Добавляем теги // Проверяем, является ли это форматированием списка или цитаты
newText = const isListFormatting = /^[-*+]\s|^\d+\.\s|^- \[ \]\s|^>\s/.test(before);
content.substring(0, start) + const isMultiline = selectedText.includes("\n");
before +
selectedText + if (isListFormatting && isMultiline) {
after + // Обрабатываем многострочное выделение для списков
content.substring(end); const lines = selectedText.split("\n");
newStart = start + before.length; let processedLines: string[] = [];
newEnd = end + before.length; let currentNumber = 1;
let isFirstNonEmptyLine = true;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const trimmedLine = line.trim();
// Пропускаем пустые строки
if (trimmedLine === "") {
processedLines.push(line);
continue;
}
// Определяем отступ текущей строки
const indentMatch = line.match(/^(\s*)/);
const indent = indentMatch ? indentMatch[1] : "";
// Обрабатываем в зависимости от типа маркера
if (before.startsWith("- [ ]")) {
// Чекбокс
processedLines.push(indent + "- [ ] " + trimmedLine);
} else if (before.startsWith("- ")) {
// Маркированный список
processedLines.push(indent + "- " + trimmedLine);
} else if (before.match(/^\d+\.\s/)) {
// Нумерованный список - извлекаем начальный номер
const numberMatch = before.match(/^(\d+)\.\s/);
if (numberMatch && isFirstNonEmptyLine) {
// Для первой непустой строки используем номер из маркера
currentNumber = parseInt(numberMatch[1]);
isFirstNonEmptyLine = false;
} else if (isFirstNonEmptyLine) {
// Если маркера нет, начинаем с 1
currentNumber = 1;
isFirstNonEmptyLine = false;
}
processedLines.push(indent + currentNumber + ". " + trimmedLine);
currentNumber++;
} else if (before.startsWith("> ")) {
// Цитата
processedLines.push(indent + "> " + trimmedLine);
} else {
// Для других форматов просто добавляем маркер
processedLines.push(indent + before + trimmedLine);
}
}
const processedText = processedLines.join("\n");
newText =
content.substring(0, start) +
processedText +
content.substring(end);
newStart = start + before.length;
newEnd = start + processedText.length;
} else {
// Добавляем теги обычным способом
newText =
content.substring(0, start) +
before +
selectedText +
after +
content.substring(end);
newStart = start + before.length;
newEnd = end + before.length;
}
} }
setContent(newText); setContent(newText);

View File

@ -416,15 +416,79 @@ export const NoteItem: React.FC<NoteItemProps> = ({
newEnd = start + innerText.length; newEnd = start + innerText.length;
} }
} else { } else {
// Добавляем теги // Проверяем, является ли это форматированием списка или цитаты
newText = const isListFormatting = /^[-*+]\s|^\d+\.\s|^- \[ \]\s|^>\s/.test(before);
editContent.substring(0, start) + const isMultiline = selectedText.includes("\n");
before +
selectedText + if (isListFormatting && isMultiline) {
after + // Обрабатываем многострочное выделение для списков
editContent.substring(end); const lines = selectedText.split("\n");
newStart = start + before.length; let processedLines: string[] = [];
newEnd = end + before.length; let currentNumber = 1;
let isFirstNonEmptyLine = true;
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const trimmedLine = line.trim();
// Пропускаем пустые строки
if (trimmedLine === "") {
processedLines.push(line);
continue;
}
// Определяем отступ текущей строки
const indentMatch = line.match(/^(\s*)/);
const indent = indentMatch ? indentMatch[1] : "";
// Обрабатываем в зависимости от типа маркера
if (before.startsWith("- [ ]")) {
// Чекбокс
processedLines.push(indent + "- [ ] " + trimmedLine);
} else if (before.startsWith("- ")) {
// Маркированный список
processedLines.push(indent + "- " + trimmedLine);
} else if (before.match(/^\d+\.\s/)) {
// Нумерованный список - извлекаем начальный номер
const numberMatch = before.match(/^(\d+)\.\s/);
if (numberMatch && isFirstNonEmptyLine) {
// Для первой непустой строки используем номер из маркера
currentNumber = parseInt(numberMatch[1]);
isFirstNonEmptyLine = false;
} else if (isFirstNonEmptyLine) {
// Если маркера нет, начинаем с 1
currentNumber = 1;
isFirstNonEmptyLine = false;
}
processedLines.push(indent + currentNumber + ". " + trimmedLine);
currentNumber++;
} else if (before.startsWith("> ")) {
// Цитата
processedLines.push(indent + "> " + trimmedLine);
} else {
// Для других форматов просто добавляем маркер
processedLines.push(indent + before + trimmedLine);
}
}
const processedText = processedLines.join("\n");
newText =
editContent.substring(0, start) +
processedText +
editContent.substring(end);
newStart = start + before.length;
newEnd = start + processedText.length;
} else {
// Добавляем теги обычным способом
newText =
editContent.substring(0, start) +
before +
selectedText +
after +
editContent.substring(end);
newStart = start + before.length;
newEnd = end + before.length;
}
} }
setEditContent(newText); setEditContent(newText);