Skip to content
Closed

hw-5 #1360

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
f953c37
Test
drdic Aug 11, 2025
4b61831
test2
drdic Aug 11, 2025
d33ac8a
Находим элементы и добавляем обработчик кнопки
drdic Aug 11, 2025
8bd0dd3
Форматируем дату и время
drdic Aug 11, 2025
4bb3903
Создание html нового комментария
drdic Aug 11, 2025
81af333
Добавляем коммент через InnerHTML
drdic Aug 11, 2025
6ca5d63
Очищаем формы
drdic Aug 11, 2025
0c91bf4
Добавляем обработчики изменений полей
drdic Aug 11, 2025
51725f1
в css добавил мигание красной рамки при ошибке ввода
drdic Aug 11, 2025
ad14618
Добавил массив комментариев и функцию рендера
drdic Aug 13, 2025
342b846
Вешаем обработчики лайков, добавляем.
drdic Aug 13, 2025
d519b81
Модифицируем обработчик добавления комментария
drdic Aug 13, 2025
25e2c05
заменяем innerHTML на добавление в массив
drdic Aug 13, 2025
e0e71ed
вызываем рендер вместо прямого добавления
drdic Aug 13, 2025
6cd5a90
И инициализируем рендер при загрузке
drdic Aug 13, 2025
6d4597f
Причёсывание...
drdic Aug 13, 2025
c18129b
добавляем переменную для хранения id комментария на который отвечаем
drdic Aug 14, 2025
52bc3a5
Добавляем обработчики кликов на комментарии
drdic Aug 14, 2025
02ae18c
Игнорим клики на лайки
drdic Aug 14, 2025
4f673b6
Подставляем текст комментария для ответа
drdic Aug 14, 2025
1ce4c87
Добавляем stopPropagation чтобы клики на комменты не вызывали ответ
drdic Aug 14, 2025
0047b5f
Сбрасываем флаг ответа после отправки
drdic Aug 14, 2025
061c81a
ввод функции экранирования html тегов
drdic Aug 14, 2025
dfe3a78
Незначительная доработка
drdic Aug 14, 2025
a897f9d
Причёсываем код....
drdic Aug 14, 2025
b039141
вынес js код в отдельный файл
drdic Sep 10, 2025
dbaf121
исправление
drdic Sep 10, 2025
138279f
Добавлены функции и файлы для выполнения hw-4 (api1)
drdic Sep 12, 2025
0b0cbc3
Добавил связь с сервером api, удалил старый массив комментариев
drdic Oct 8, 2025
c10eeda
После функции escapeHtml добавил функцию загрузки
drdic Oct 8, 2025
6730dda
Заменил функцию renderComments
drdic Oct 8, 2025
7b07e29
Заменил блок addButton.addEventListener
drdic Oct 8, 2025
7bbcbb1
Заменил вызов render на load
drdic Oct 8, 2025
4901a48
Убрал закомментированное
drdic Oct 8, 2025
06ebc20
Добавил стили в css
drdic Oct 8, 2025
3faf67c
Причесал.
drdic Oct 8, 2025
0de273c
Добавил состояние загрузки комментариев
drdic Oct 8, 2025
57daf33
Внёс правки преподавателя.
drdic Oct 9, 2025
eb60e07
Убрал комментарии.
drdic Oct 9, 2025
1c5c399
исправил цитирование комментариев.
drdic Oct 9, 2025
27d6fd8
Выполнение 1-го задания hw-5
drdic Oct 9, 2025
43c7a10
- renderComments и initAddCommentListener теперь без аргументов
drdic Oct 13, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
3 changes: 3 additions & 0 deletions .prettierrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
tabWidth: 4
semi: false
singleQuote: true
12 changes: 12 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import globals from 'globals'
import pluginJs from '@eslint/js'
import config from 'eslint-config-prettier'
import plugin from 'eslint-plugin-prettier/recommended'

/** @type {import('eslint').Linter.Config[]} */
export default [
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
config,
plugin,
]
90 changes: 25 additions & 65 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,71 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<title>Проект "Комменты"</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="styles.css" />
</head>

<body>
<div class="container">
<ul class="comments">
<li class="comment">
<div class="comment-header">
<div>Глеб Фокин</div>
<div>12.02.22 12:18</div>
</div>
<div class="comment-body">
<div class="comment-text">
Это будет первый комментарий на этой странице
</div>
</div>
<div class="comment-footer">
<div class="likes">
<span class="likes-counter">3</span>
<button class="like-button"></button>
</div>
</div>
</li>
<li class="comment">
<div class="comment-header">
<div>Варвара Н.</div>
<div>13.02.22 19:22</div>
</div>
<div class="comment-body">
<div class="comment-text">
Мне нравится как оформлена эта страница! ❤
</div>
</div>
<div class="comment-footer">
<div class="likes">
<span class="likes-counter">75</span>
<button class="like-button -active-like"></button>
</div>
</div>
</li>
</ul>
<div class="add-form">
<input
type="text"
class="add-form-name"
placeholder="Введите ваше имя"
/>
<textarea
type="textarea"
class="add-form-text"
placeholder="Введите ваш коментарий"
rows="4"
></textarea>
<div class="add-form-row">
<button class="add-form-button">Написать</button>
</div>
<head>
<title>Проект "Комменты"</title>
<meta charset="utf-8" />
<link rel="stylesheet" href="styles.css" />
</head>

<body>
<div class="container">
<ul class="comments">
<!-- Комментарии будут загружаться через JavaScript -->
</ul>
<div id="comments-loading" class="loading" style="display: none;">
Пожалуйста подождите, загружаю комментарии...
</div>
</ul>
<div class="add-form">
<input type="text" class="add-form-name" placeholder="Введите ваше имя" />
<textarea type="textarea" class="add-form-text" placeholder="Введите ваш коментарий" rows="4"></textarea>
<div class="add-form-row">
<button class="add-form-button">Написать</button>
</div>
</div>
</body>
</div>
</body>

<script type="module" src="./main.js"></script>

<script>
"use strict";
// Код писать здесь
console.log("It works!");
</script>
</html>
</html>
41 changes: 41 additions & 0 deletions main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { comments } from './modules/data.js';
import { getComments } from './modules/api.js';
import { renderComments } from './modules/render.js';
import { initAddCommentListener } from './modules/listeners.js'; // импорт изменен

const commentsList = document.querySelector('.comments');
const commentsLoading = document.getElementById('comments-loading');

// Функции для управления загрузкой комментариев
function showCommentsLoading() {
commentsLoading.style.display = 'block';
commentsList.style.opacity = '0.3'; // Затемняем вместо скрытия
}

function hideCommentsLoading() {
commentsLoading.style.display = 'none';
commentsList.style.opacity = '1'; // Возвращаем нормальную прозрачность
}

async function loadComments() {
try {
// ПОКАЗЫВАЕМ загрузку только при СТАРТЕ приложения
showCommentsLoading();

comments.length = 0;
const freshComments = await getComments();
comments.push(...freshComments);
renderComments(); // без аргументов!

} catch (error) {
commentsList.innerHTML = '<div class="error">Не удалось загрузить комментарии</div>';
} finally {
// ВСЕГДА скрываем загрузку
hideCommentsLoading();
}
}

loadComments();
initAddCommentListener(); // вызов изменен и без аргументов

export { loadComments };
24 changes: 24 additions & 0 deletions modules/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
const API_BASE_URL = "https://wedev-api.sky.pro/api/v1";
const PERSONAL_KEY = "eduard-zakharevskiy";
const API_URL = `${API_BASE_URL}/${PERSONAL_KEY}/comments`;

export async function getComments() {
const response = await fetch(API_URL);
if (!response.ok) throw new Error('Ошибка загрузки');
const data = await response.json();
return data.comments;
}

export async function addComment({ name, text }) {
const response = await fetch(API_URL, {
method: 'POST',
body: JSON.stringify({ name, text })
});

if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Ошибка сервера');
}

return await response.json();
}
2 changes: 2 additions & 0 deletions modules/data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export let comments = [];
export let replyingTo = null;
83 changes: 83 additions & 0 deletions modules/listeners.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { loadComments } from '../main.js'; // импортируем LoadComments
import { comments, replyingTo } from './data.js';
import { addComment } from './api.js';
import { renderComments } from './render.js';
import { escapeHtml } from './utils.js';

export function initAddCommentListener() {
const nameInput = document.querySelector('.add-form-name');
const textInput = document.querySelector('.add-form-text');
const addButton = document.querySelector('.add-form-button');

addButton.addEventListener('click', async () => {
const safeName = escapeHtml(nameInput.value.trim());
const safeText = escapeHtml(textInput.value.trim());

if (!safeName || !safeText) {
if (!safeName) nameInput.classList.add('error');
if (!safeText) textInput.classList.add('error');
return;
}

addButton.disabled = true;
addButton.textContent = 'Добавляем...';

try {
await addComment({ name: safeName, text: safeText });
nameInput.value = '';
textInput.value = '';
nameInput.classList.remove('error');
textInput.classList.remove('error');
await loadComments(); // используем импортированную функцию
} catch (error) {
alert(error.message);
} finally {
addButton.disabled = false;
addButton.textContent = 'Написать';
}
});

nameInput.addEventListener('input', () => {
if (nameInput.value.trim()) nameInput.classList.remove('error');
});

textInput.addEventListener('input', () => {
if (textInput.value.trim()) textInput.classList.remove('error');
});
}

export function initLikeListeners() {
document.querySelectorAll('.like-button').forEach(button => {
button.addEventListener('click', (event) => {
const commentId = parseInt(event.target.closest('.comment').dataset.id);
const comment = comments.find(c => c.id === commentId);

if (comment) {
comment.isLiked = !comment.isLiked;
comment.likes += comment.isLiked ? 1 : -1;
renderComments();
}
});
});
}

export function initQuoteListeners() {
document.querySelectorAll('.comment').forEach(commentElement => {
commentElement.addEventListener('click', function (event) {
if (event.target.closest('.like-button')) {
return;
}

const commentId = parseInt(this.dataset.id);
const comment = comments.find(c => c.id === commentId);

if (comment) {
const textInput = document.querySelector('.add-form-text');
const quoteText = `> ${comment.author.name}: ${comment.text}\n\n`;
textInput.value = quoteText;
textInput.focus();
textInput.scrollIntoView({ behavior: 'smooth' });
}
});
});
}
28 changes: 28 additions & 0 deletions modules/render.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { comments } from './data.js';
import { initLikeListeners, initQuoteListeners } from './listeners.js';

export function renderComments() {
const commentsList = document.querySelector('.comments');

commentsList.innerHTML = comments.map(comment => `
<li class="comment" data-id="${comment.id}">
<div class="comment-header">
<div>${comment.author.name}</div>
<div>${new Date(comment.date).toLocaleString()}</div>
</div>
<div class="comment-body">
<div class="comment-text">${comment.text.replace(/\n/g, '<br>')}</div>
</div>
<div class="comment-footer">
<div class="likes">
<span class="likes-counter">${comment.likes}</span>
<button class="like-button ${comment.isLiked ? '-active-like' : ''}"></button>
</div>
</div>
</li>
`).join('');

// вызываем функции из listeners.js вместо кода здесь
initLikeListeners();
initQuoteListeners();
}
8 changes: 8 additions & 0 deletions modules/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}
Loading