Добавлены функции для улучшения обработки тегов и редактирования заметок

- Реализована проверка на наличие символа # внутри HTML-атрибутов при извлечении тегов.
- Добавлена кнопка отмены редактирования с соответствующей логикой для возврата к исходному состоянию заметки.
- Обновлены обработчики событий для поддержки новой кнопки отмены и улучшения пользовательского интерфейса.
This commit is contained in:
Fovway 2025-10-22 23:39:52 +07:00
parent 083ac11ab1
commit 05706a7e35

View File

@ -108,6 +108,45 @@ function extractTags(content) {
let match; let match;
while ((match = tagRegex.exec(content)) !== null) { while ((match = tagRegex.exec(content)) !== null) {
const matchIndex = match.index;
// Проверяем, не находится ли # внутри HTML-атрибута
const beforeContext = content.substring(
Math.max(0, matchIndex - 100),
matchIndex
);
const afterContext = content.substring(
matchIndex + match[0].length,
Math.min(content.length, matchIndex + match[0].length + 100)
);
// Проверяем, есть ли признаки HTML-атрибута (например, style="color: #...)
const lastOpenTag = beforeContext.lastIndexOf("<");
const lastCloseTag = beforeContext.lastIndexOf(">");
// Если внутри HTML-тега, пропускаем
if (lastOpenTag > lastCloseTag) {
continue;
}
// Проверяем наличие = и кавычки перед #
const lastQuote = Math.max(
beforeContext.lastIndexOf('"'),
beforeContext.lastIndexOf("'")
);
const lastEquals = beforeContext.lastIndexOf("=");
// Если перед # есть = и кавычка, и после есть закрывающая кавычка
if (lastEquals > -1 && lastQuote > lastEquals) {
const nextQuote = Math.min(
afterContext.indexOf('"') !== -1 ? afterContext.indexOf('"') : Infinity,
afterContext.indexOf("'") !== -1 ? afterContext.indexOf("'") : Infinity
);
if (nextQuote !== Infinity) {
continue; // Пропускаем, это часть HTML-атрибута
}
}
const tag = match[1].toLowerCase(); const tag = match[1].toLowerCase();
if (!tags.includes(tag)) { if (!tags.includes(tag)) {
tags.push(tag); tags.push(tag);
@ -149,6 +188,31 @@ function makeTagsClickable(content) {
continue; // Пропускаем этот тег continue; // Пропускаем этот тег
} }
// Дополнительная проверка: не находится ли # внутри HTML-атрибута (например, style="color: #ff0000")
// Ищем последний символ кавычки перед текущей позицией
const beforeContext = beforeTag.substring(Math.max(0, match.index - 100));
const lastQuote = Math.max(
beforeContext.lastIndexOf('"'),
beforeContext.lastIndexOf("'")
);
const lastEquals = beforeContext.lastIndexOf("=");
// Если перед # есть = и кавычка, и нет закрывающей кавычки после =, то # находится в атрибуте
if (lastEquals > -1 && lastQuote > lastEquals) {
const afterContext = afterTag.substring(
0,
Math.min(100, afterTag.length)
);
const nextQuote = Math.min(
afterContext.indexOf('"') !== -1 ? afterContext.indexOf('"') : Infinity,
afterContext.indexOf("'") !== -1 ? afterContext.indexOf("'") : Infinity
);
// Если нашли закрывающую кавычку, значит # внутри атрибута
if (nextQuote !== Infinity) {
continue; // Пропускаем этот тег
}
}
// Заменяем тег на кликабельный элемент // Заменяем тег на кликабельный элемент
const replacement = `<span class="tag-in-note" data-tag="${match.tag}">${match.fullMatch}</span>`; const replacement = `<span class="tag-in-note" data-tag="${match.tag}">${match.fullMatch}</span>`;
result = beforeTag + replacement + afterTag; result = beforeTag + replacement + afterTag;
@ -1489,12 +1553,19 @@ function addNoteEventListeners() {
saveEditBtn.textContent = "Сохранить"; saveEditBtn.textContent = "Сохранить";
saveEditBtn.classList.add("btnSave"); saveEditBtn.classList.add("btnSave");
// Кнопка отмены
const cancelEditBtn = document.createElement("button");
cancelEditBtn.textContent = "Отмена";
cancelEditBtn.classList.add("btnSave");
cancelEditBtn.style.marginLeft = "8px";
// Подсказка о горячей клавише // Подсказка о горячей клавише
const saveHint = document.createElement("span"); const saveHint = document.createElement("span");
saveHint.classList.add("save-hint"); saveHint.classList.add("save-hint");
saveHint.textContent = "или нажмите Alt + Enter"; saveHint.textContent = "или нажмите Alt + Enter";
saveButtonContainer.appendChild(saveEditBtn); saveButtonContainer.appendChild(saveEditBtn);
saveButtonContainer.appendChild(cancelEditBtn);
saveButtonContainer.appendChild(saveHint); saveButtonContainer.appendChild(saveHint);
// Функция обновления превью изображений для режима редактирования // Функция обновления превью изображений для режима редактирования
@ -1593,11 +1664,42 @@ function addNoteEventListeners() {
} }
}; };
// Функция отмены редактирования
const cancelEditNote = async function () {
const originalMarkdown = noteContent.dataset.originalContent || "";
const hasTextChanges = textarea.value !== originalMarkdown;
const hasNewImages = editSelectedImages.length > 0;
if (hasTextChanges || hasNewImages) {
const ok = confirm("Отменить изменения?");
if (!ok) return;
}
// Очистить выбранные новые изображения и превью
editSelectedImages.length = 0;
if (editImagePreviewContainer) {
editImagePreviewContainer.style.display = "none";
}
if (editImagePreviewList) {
editImagePreviewList.innerHTML = "";
}
if (editImageInput) {
editImageInput.value = "";
}
// Перерисовать заметки, вернув исходное состояние
await loadNotes(true);
};
// Обработчик горячей клавиши Alt+Enter для сохранения редактирования // Обработчик горячей клавиши Alt+Enter для сохранения редактирования
textarea.addEventListener("keydown", function (event) { textarea.addEventListener("keydown", function (event) {
if (event.altKey && event.key === "Enter") { if (event.altKey && event.key === "Enter") {
event.preventDefault(); event.preventDefault();
saveEditNote(); saveEditNote();
} else if (event.key === "Escape") {
event.stopPropagation();
event.preventDefault();
cancelEditNote();
} }
}); });
@ -1654,6 +1756,9 @@ function addNoteEventListeners() {
// Обработчик сохранения редактирования // Обработчик сохранения редактирования
saveEditBtn.addEventListener("click", saveEditNote); saveEditBtn.addEventListener("click", saveEditNote);
// Обработчик отмены редактирования
cancelEditBtn.addEventListener("click", cancelEditNote);
}); });
}); });
} }