✨ Добавлена возможность загрузки и предварительного просмотра изображений при редактировании заметок
- Реализована кнопка для загрузки изображений в режиме редактирования заметок - Добавлены элементы для предварительного просмотра загруженных изображений - Обновлена функция сохранения заметки для поддержки изображений - Добавлены обработчики для управления загруженными изображениями, включая удаление и очистку
This commit is contained in:
parent
092c01dff4
commit
431d51c483
134
public/app.js
134
public/app.js
@ -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);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user