Добавлена возможность загрузки и предварительного просмотра изображений при редактировании заметок

- Реализована кнопка для загрузки изображений в режиме редактирования заметок
- Добавлены элементы для предварительного просмотра загруженных изображений
- Обновлена функция сохранения заметки для поддержки изображений
- Добавлены обработчики для управления загруженными изображениями, включая удаление и очистку
This commit is contained in:
Fovway 2025-10-20 07:53:43 +07:00
parent 092c01dff4
commit 431d51c483

View File

@ -815,6 +815,7 @@ function addNoteEventListeners() {
{ id: "editQuoteBtn", icon: "mdi:format-quote-close", tag: "> " }, { id: "editQuoteBtn", icon: "mdi:format-quote-close", tag: "> " },
{ id: "editCodeBtn", icon: "mdi:code-tags", tag: "`" }, { id: "editCodeBtn", icon: "mdi:code-tags", tag: "`" },
{ id: "editLinkBtn", icon: "mdi:link", tag: "[Текст ссылки](URL)" }, { id: "editLinkBtn", icon: "mdi:link", tag: "[Текст ссылки](URL)" },
{ id: "editImageBtn", icon: "mdi:image-plus", tag: "image" },
]; ];
markdownButtons.forEach((button) => { markdownButtons.forEach((button) => {
@ -837,6 +838,36 @@ function addNoteEventListeners() {
autoExpandTextarea(textarea); autoExpandTextarea(textarea);
}); });
// Создаем элементы для загрузки изображений в режиме редактирования
const editImageInput = document.createElement("input");
editImageInput.type = "file";
editImageInput.accept = "image/*";
editImageInput.multiple = true;
editImageInput.style.display = "none";
editImageInput.id = `editImageInput-${noteId}`;
const editImagePreviewContainer = document.createElement("div");
editImagePreviewContainer.id = `editImagePreviewContainer-${noteId}`;
editImagePreviewContainer.classList.add("image-preview-container");
editImagePreviewContainer.style.display = "none";
const editImagePreviewHeader = document.createElement("div");
editImagePreviewHeader.classList.add("image-preview-header");
editImagePreviewHeader.innerHTML = `
<span>Новые изображения:</span>
<button type="button" class="clear-images-btn" id="editClearImagesBtn-${noteId}">Очистить все</button>
`;
const editImagePreviewList = document.createElement("div");
editImagePreviewList.id = `editImagePreviewList-${noteId}`;
editImagePreviewList.classList.add("image-preview-list");
editImagePreviewContainer.appendChild(editImagePreviewHeader);
editImagePreviewContainer.appendChild(editImagePreviewList);
// Массив для хранения новых изображений в режиме редактирования
const editSelectedImages = [];
// Контейнер для кнопки сохранения и подсказки // Контейнер для кнопки сохранения и подсказки
const saveButtonContainer = document.createElement("div"); const saveButtonContainer = document.createElement("div");
saveButtonContainer.classList.add("save-button-container"); saveButtonContainer.classList.add("save-button-container");
@ -854,9 +885,73 @@ function addNoteEventListeners() {
saveButtonContainer.appendChild(saveEditBtn); saveButtonContainer.appendChild(saveEditBtn);
saveButtonContainer.appendChild(saveHint); saveButtonContainer.appendChild(saveHint);
// Функция обновления превью изображений для режима редактирования
const updateEditImagePreview = function() {
if (editSelectedImages.length === 0) {
editImagePreviewContainer.style.display = "none";
return;
}
editImagePreviewContainer.style.display = "block";
editImagePreviewList.innerHTML = "";
editSelectedImages.forEach((file, index) => {
const reader = new FileReader();
reader.onload = function (e) {
const previewItem = document.createElement("div");
previewItem.className = "image-preview-item";
previewItem.innerHTML = `
<img src="${e.target.result}" alt="Preview">
<button class="remove-image-btn" data-index="${index}">×</button>
<div class="image-info">${file.name}</div>
`;
editImagePreviewList.appendChild(previewItem);
// Обработчик удаления изображения
const removeBtn = previewItem.querySelector(".remove-image-btn");
removeBtn.addEventListener("click", function () {
editSelectedImages.splice(index, 1);
updateEditImagePreview();
});
};
reader.readAsDataURL(file);
});
};
// Функция загрузки изображений для режима редактирования
const uploadEditImages = async function(noteId) {
if (editSelectedImages.length === 0) {
return [];
}
const formData = new FormData();
editSelectedImages.forEach(file => {
formData.append("images", file);
});
try {
const response = await fetch(`/api/notes/${noteId}/images`, {
method: "POST",
body: formData,
});
if (!response.ok) {
throw new Error("Ошибка загрузки изображений");
}
const result = await response.json();
return result.images || [];
} catch (error) {
console.error("Ошибка загрузки изображений:", error);
return [];
}
};
// Функция сохранения для редактирования // Функция сохранения для редактирования
const saveEditNote = async function () { const saveEditNote = async function () {
if (textarea.value.trim() !== "") { if (textarea.value.trim() !== "" || editSelectedImages.length > 0) {
try { try {
const { date, time } = getFormattedDateTime(); const { date, time } = getFormattedDateTime();
const response = await fetch(`/api/notes/${noteId}`, { const response = await fetch(`/api/notes/${noteId}`, {
@ -865,7 +960,7 @@ function addNoteEventListeners() {
"Content-Type": "application/json", "Content-Type": "application/json",
}, },
body: JSON.stringify({ body: JSON.stringify({
content: textarea.value, content: textarea.value || " ", // Минимальный контент, если только изображения
date: date, date: date,
time: time, time: time,
}), }),
@ -875,6 +970,11 @@ function addNoteEventListeners() {
throw new Error("Ошибка сохранения заметки"); throw new Error("Ошибка сохранения заметки");
} }
// Загружаем новые изображения, если они есть
if (editSelectedImages.length > 0) {
await uploadEditImages(noteId);
}
// Перезагружаем заметки // Перезагружаем заметки
await loadNotes(true); await loadNotes(true);
} catch (error) { } catch (error) {
@ -892,10 +992,31 @@ function addNoteEventListeners() {
} }
}); });
// Очищаем текущий контент и вставляем markdown кнопки, textarea и контейнер с кнопкой сохранить // Обработчики для загрузки изображений в режиме редактирования
editImageInput.addEventListener("change", function (event) {
const files = Array.from(event.target.files);
files.forEach(file => {
if (file.type.startsWith('image/')) {
editSelectedImages.push(file);
}
});
updateEditImagePreview();
});
// Обработчик очистки всех изображений в режиме редактирования
const editClearImagesBtn = editImagePreviewHeader.querySelector(`#editClearImagesBtn-${noteId}`);
editClearImagesBtn.addEventListener("click", function () {
editSelectedImages.length = 0;
updateEditImagePreview();
editImageInput.value = "";
});
// Очищаем текущий контент и вставляем markdown кнопки, textarea, элементы для изображений и контейнер с кнопкой сохранить
noteContent.innerHTML = ""; noteContent.innerHTML = "";
noteContent.appendChild(markdownButtonsContainer); noteContent.appendChild(markdownButtonsContainer);
noteContent.appendChild(textarea); noteContent.appendChild(textarea);
noteContent.appendChild(editImageInput);
noteContent.appendChild(editImagePreviewContainer);
noteContent.appendChild(saveButtonContainer); noteContent.appendChild(saveButtonContainer);
// Применяем авторасширение после добавления в DOM // Применяем авторасширение после добавления в DOM
@ -908,7 +1029,12 @@ function addNoteEventListeners() {
markdownButtons.forEach((button) => { markdownButtons.forEach((button) => {
const btn = document.getElementById(button.id); const btn = document.getElementById(button.id);
btn.addEventListener("click", function () { btn.addEventListener("click", function () {
insertMarkdownForEdit(textarea, button.tag); if (button.tag === "image") {
// Для кнопки изображения открываем диалог выбора файлов
editImageInput.click();
} else {
insertMarkdownForEdit(textarea, button.tag);
}
}); });
}); });