// DOM элементы const noteInput = document.getElementById("noteInput"); const saveBtn = document.getElementById("saveBtn"); const notesList = document.getElementById("notesList"); // Получаем кнопки markdown const boldBtn = document.getElementById("boldBtn"); const italicBtn = document.getElementById("italicBtn"); const headerBtn = document.getElementById("headerBtn"); const listBtn = document.getElementById("listBtn"); const quoteBtn = document.getElementById("quoteBtn"); const codeBtn = document.getElementById("codeBtn"); const linkBtn = document.getElementById("linkBtn"); // Функция для получения текущей даты и времени function getFormattedDateTime() { let now = new Date(); let day = String(now.getDate()).padStart(2, "0"); let month = String(now.getMonth() + 1).padStart(2, "0"); let year = now.getFullYear(); let hours = String(now.getHours()).padStart(2, "0"); let minutes = String(now.getMinutes()).padStart(2, "0"); return { date: `${day}.${month}.${year}`, time: `${hours}:${minutes}`, }; } // Функция для авторасширения текстового поля function autoExpandTextarea(textarea) { textarea.style.height = "auto"; textarea.style.height = textarea.scrollHeight + "px"; } // Привязываем авторасширение к текстовому полю для создания заметки noteInput.addEventListener("input", function () { autoExpandTextarea(noteInput); }); // Изначально запускаем для установки правильной высоты autoExpandTextarea(noteInput); // Функция для вставки markdown function insertMarkdown(tag) { const start = noteInput.selectionStart; const end = noteInput.selectionEnd; const text = noteInput.value; const before = text.substring(0, start); const selected = text.substring(start, end); const after = text.substring(end); if (selected.startsWith(tag) && selected.endsWith(tag)) { // Если теги уже есть, удаляем их noteInput.value = `${before}${selected.slice( tag.length, -tag.length )}${after}`; noteInput.setSelectionRange(start, end - 2 * tag.length); } else if (selected.trim() === "") { // Если текст не выделен if (tag === "[Текст ссылки](URL)") { // Для ссылок создаем шаблон с двумя кавычками noteInput.value = `${before}[Текст ссылки](URL)${after}`; const cursorPosition = start + 1; // Помещаем курсор внутрь текста ссылки noteInput.setSelectionRange(cursorPosition, cursorPosition + 12); } else if (tag === "- " || tag === "> " || tag === "# ") { // Для списка, цитаты и заголовка помещаем курсор после `- `, `> ` или `# ` noteInput.value = `${before}${tag}${after}`; const cursorPosition = start + tag.length; noteInput.setSelectionRange(cursorPosition, cursorPosition); } else { // Для остальных типов создаем два тега noteInput.value = `${before}${tag}${tag}${after}`; const cursorPosition = start + tag.length; noteInput.setSelectionRange(cursorPosition, cursorPosition); } } else { // Если текст выделен if (tag === "[Текст ссылки](URL)") { // Для ссылок используем выделенный текст вместо "Текст ссылки" noteInput.value = `${before}[${selected}](URL)${after}`; const cursorPosition = start + selected.length + 3; // Помещаем курсор в URL noteInput.setSelectionRange(cursorPosition, cursorPosition + 3); } else if (tag === "- " || tag === "> " || tag === "# ") { // Для списка, цитаты и заголовка добавляем `- `, `> ` или `# ` перед выделенным текстом noteInput.value = `${before}${tag}${selected}${after}`; const cursorPosition = start + tag.length + selected.length; noteInput.setSelectionRange(cursorPosition, cursorPosition); } else { // Для остальных типов оборачиваем выделенный текст noteInput.value = `${before}${tag}${selected}${tag}${after}`; const cursorPosition = start + tag.length + selected.length + tag.length; noteInput.setSelectionRange(cursorPosition, cursorPosition); } } noteInput.focus(); } // Функция для вставки markdown в режиме редактирования function insertMarkdownForEdit(textarea, tag) { const start = textarea.selectionStart; const end = textarea.selectionEnd; const text = textarea.value; const before = text.substring(0, start); const selected = text.substring(start, end); const after = text.substring(end); if (selected.startsWith(tag) && selected.endsWith(tag)) { // Если теги уже есть, удаляем их textarea.value = `${before}${selected.slice( tag.length, -tag.length )}${after}`; textarea.setSelectionRange(start, end - 2 * tag.length); } else if (selected.trim() === "") { // Если текст не выделен if (tag === "[Текст ссылки](URL)") { // Для ссылок создаем шаблон с двумя кавычками textarea.value = `${before}[Текст ссылки](URL)${after}`; const cursorPosition = start + 1; // Помещаем курсор внутрь текста ссылки textarea.setSelectionRange(cursorPosition, cursorPosition + 12); } else if (tag === "- " || tag === "> " || tag === "# ") { // Для списка, цитаты и заголовка помещаем курсор после `- `, `> ` или `# ` textarea.value = `${before}${tag}${after}`; const cursorPosition = start + tag.length; textarea.setSelectionRange(cursorPosition, cursorPosition); } else { // Для остальных типов создаем два тега textarea.value = `${before}${tag}${tag}${after}`; const cursorPosition = start + tag.length; textarea.setSelectionRange(cursorPosition, cursorPosition); } } else { // Если текст выделен if (tag === "[Текст ссылки](URL)") { // Для ссылок используем выделенный текст вместо "Текст ссылки" textarea.value = `${before}[${selected}](URL)${after}`; const cursorPosition = start + selected.length + 3; // Помещаем курсор в URL textarea.setSelectionRange(cursorPosition, cursorPosition + 3); } else if (tag === "- " || tag === "> " || tag === "# ") { // Для списка, цитаты и заголовка добавляем `- `, `> ` или `# ` перед выделенным текстом textarea.value = `${before}${tag}${selected}${after}`; const cursorPosition = start + tag.length + selected.length; textarea.setSelectionRange(cursorPosition, cursorPosition); } else { // Для остальных типов оборачиваем выделенный текст textarea.value = `${before}${tag}${selected}${tag}${after}`; const cursorPosition = start + tag.length + selected.length + tag.length; textarea.setSelectionRange(cursorPosition, cursorPosition); } } textarea.focus(); } // Обработчики для кнопок markdown boldBtn.addEventListener("click", function () { insertMarkdown("**"); }); italicBtn.addEventListener("click", function () { insertMarkdown("*"); }); headerBtn.addEventListener("click", function () { insertMarkdown("# "); }); listBtn.addEventListener("click", function () { insertMarkdown("- "); }); quoteBtn.addEventListener("click", function () { insertMarkdown("> "); }); codeBtn.addEventListener("click", function () { insertMarkdown("`"); }); linkBtn.addEventListener("click", function () { insertMarkdown("[Текст ссылки](URL)"); }); // Функция для загрузки заметок с сервера async function loadNotes() { try { const response = await fetch("/api/notes"); if (!response.ok) { throw new Error("Ошибка загрузки заметок"); } const notes = await response.json(); renderNotes(notes); } catch (error) { console.error("Ошибка:", error); notesList.innerHTML = "

Ошибка загрузки заметок

"; } } // Функция для отображения заметок function renderNotes(notes) { notesList.innerHTML = ""; // Итерируемся по заметкам в обычном порядке, чтобы новые были сверху notes.forEach(function (note) { const noteHtml = `
${note.date} ${note.time}
Редактировать
Удалить
${marked.parse(note.content)}
`; notesList.insertAdjacentHTML("afterbegin", noteHtml); }); // Добавляем обработчики событий для кнопок редактирования и удаления addNoteEventListeners(); } // Функция для добавления обработчиков событий к заметкам function addNoteEventListeners() { // Обработчик удаления document.querySelectorAll("#deleteBtn").forEach((btn) => { btn.addEventListener("click", async function (event) { const noteId = event.target.dataset.id; if (confirm("Вы уверены, что хотите удалить эту заметку?")) { try { const response = await fetch(`/api/notes/${noteId}`, { method: "DELETE", }); if (!response.ok) { throw new Error("Ошибка удаления заметки"); } // Перезагружаем заметки loadNotes(); } catch (error) { console.error("Ошибка:", error); alert("Ошибка удаления заметки"); } } }); }); // Обработчик редактирования document.querySelectorAll("#editBtn").forEach((btn) => { btn.addEventListener("click", function (event) { const noteId = event.target.dataset.id; const noteContainer = event.target.closest("#note"); const noteContent = noteContainer.querySelector(".textNote"); // Создаем контейнер для markdown кнопок const markdownButtonsContainer = document.createElement("div"); markdownButtonsContainer.classList.add("markdown-buttons"); // Создаем markdown кнопки const markdownButtons = [ { id: "editBoldBtn", icon: "fas fa-bold", tag: "**" }, { id: "editItalicBtn", icon: "fas fa-italic", tag: "*" }, { id: "editHeaderBtn", icon: "fas fa-heading", tag: "# " }, { id: "editListBtn", icon: "fas fa-list-ul", tag: "- " }, { id: "editQuoteBtn", icon: "fas fa-quote-right", tag: "> " }, { id: "editCodeBtn", icon: "fas fa-code", tag: "`" }, { id: "editLinkBtn", icon: "fas fa-link", tag: "[Текст ссылки](URL)" }, ]; markdownButtons.forEach((button) => { const btn = document.createElement("button"); btn.classList.add("btnMarkdown"); btn.id = button.id; btn.innerHTML = ``; markdownButtonsContainer.appendChild(btn); }); // Создаем textarea с уже существующим классом textInput const textarea = document.createElement("textarea"); textarea.classList.add("textInput"); // Получаем исходный markdown контент из data-атрибута или используем textContent как fallback textarea.value = noteContent.dataset.originalContent || noteContent.textContent; // Привязываем авторасширение к textarea для редактирования textarea.addEventListener("input", function () { autoExpandTextarea(textarea); }); autoExpandTextarea(textarea); // Кнопка сохранить const saveEditBtn = document.createElement("button"); saveEditBtn.textContent = "Сохранить"; saveEditBtn.classList.add("btnSave"); // Очищаем текущий контент и вставляем markdown кнопки, textarea и кнопку сохранить noteContent.innerHTML = ""; noteContent.appendChild(markdownButtonsContainer); noteContent.appendChild(textarea); noteContent.appendChild(saveEditBtn); // Добавляем обработчики для markdown кнопок редактирования markdownButtons.forEach((button) => { const btn = document.getElementById(button.id); btn.addEventListener("click", function () { insertMarkdownForEdit(textarea, button.tag); }); }); // Обработчик сохранения редактирования saveEditBtn.addEventListener("click", async function () { if (textarea.value.trim() !== "") { try { const { date, time } = getFormattedDateTime(); const response = await fetch(`/api/notes/${noteId}`, { method: "PUT", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ content: textarea.value, date: date, time: time, }), }); if (!response.ok) { throw new Error("Ошибка сохранения заметки"); } // Перезагружаем заметки loadNotes(); } catch (error) { console.error("Ошибка:", error); alert("Ошибка сохранения заметки"); } } }); }); }); } // Обработчик сохранения новой заметки saveBtn.addEventListener("click", async function () { if (noteInput.value.trim() !== "") { try { const { date, time } = getFormattedDateTime(); const response = await fetch("/api/notes", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify({ content: noteInput.value, date: date, time: time, }), }); if (!response.ok) { throw new Error("Ошибка сохранения заметки"); } // Очищаем поле ввода и перезагружаем заметки noteInput.value = ""; noteInput.style.height = "auto"; loadNotes(); } catch (error) { console.error("Ошибка:", error); alert("Ошибка сохранения заметки"); } } }); // Загружаем заметки при загрузке страницы document.addEventListener("DOMContentLoaded", function () { loadNotes(); });