diff --git a/public/app.js b/public/app.js index 1dc0199..82242dc 100644 --- a/public/app.js +++ b/public/app.js @@ -108,6 +108,45 @@ function extractTags(content) { let match; 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(); if (!tags.includes(tag)) { tags.push(tag); @@ -149,6 +188,31 @@ function makeTagsClickable(content) { 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 = `${match.fullMatch}`; result = beforeTag + replacement + afterTag; @@ -1489,12 +1553,19 @@ function addNoteEventListeners() { saveEditBtn.textContent = "Сохранить"; saveEditBtn.classList.add("btnSave"); + // Кнопка отмены + const cancelEditBtn = document.createElement("button"); + cancelEditBtn.textContent = "Отмена"; + cancelEditBtn.classList.add("btnSave"); + cancelEditBtn.style.marginLeft = "8px"; + // Подсказка о горячей клавише const saveHint = document.createElement("span"); saveHint.classList.add("save-hint"); saveHint.textContent = "или нажмите Alt + Enter"; saveButtonContainer.appendChild(saveEditBtn); + saveButtonContainer.appendChild(cancelEditBtn); 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 для сохранения редактирования textarea.addEventListener("keydown", function (event) { if (event.altKey && event.key === "Enter") { event.preventDefault(); saveEditNote(); + } else if (event.key === "Escape") { + event.stopPropagation(); + event.preventDefault(); + cancelEditNote(); } }); @@ -1654,6 +1756,9 @@ function addNoteEventListeners() { // Обработчик сохранения редактирования saveEditBtn.addEventListener("click", saveEditNote); + + // Обработчик отмены редактирования + cancelEditBtn.addEventListener("click", cancelEditNote); }); }); }