From daa0d7e6717d2201d8d6d79fbc53a0d89c019c70 Mon Sep 17 00:00:00 2001 From: Vladimir Gankin Date: Tue, 25 Mar 2025 13:55:02 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D1=80=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=20=D0=BF=D0=B5=D0=B5=D1=80=D0=BC=D0=B5=D0=BD=D0=BD=D1=8B?= =?UTF-8?q?=D1=85=20=D0=B8=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=B9=20=D1=84=D0=B0=D0=B9=D0=BB=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/comments-loader.js | 10 ++++---- js/image-filtration.js | 42 ++++++++++++++++---------------- js/images-preview-loader.js | 46 +++++++++++++++++++++++++++++++++++ js/main.js | 10 ++++---- js/pictures-preview-loader.js | 44 --------------------------------- js/show-image-fullscreen.js | 32 ++++++++++++------------ 6 files changed, 93 insertions(+), 91 deletions(-) create mode 100644 js/images-preview-loader.js delete mode 100644 js/pictures-preview-loader.js diff --git a/js/comments-loader.js b/js/comments-loader.js index b621f16..c5b1fbf 100644 --- a/js/comments-loader.js +++ b/js/comments-loader.js @@ -2,8 +2,8 @@ const SHOW_COMMENTS_STEP = 5; const commentsList = document.querySelector('.social__comments'); const commentTemplate = commentsList.querySelector('li'); -const pictureShownComments = document.querySelector('.social__comment-shown-count'); -const pictureTotalComments = document.querySelector('.social__comment-total-count'); +const imageShownComments = document.querySelector('.social__comment-shown-count'); +const imageTotalComments = document.querySelector('.social__comment-total-count'); const commentsShowMoreButton = document.querySelector('.comments-loader'); let currentComments = []; let currentCommentsCount = 0; @@ -32,15 +32,15 @@ const showNextComments = () => { commentsShowMoreButton.classList.add('hidden'); } - pictureShownComments.textContent = renderedCommentsCount; + imageShownComments.textContent = renderedCommentsCount; currentCommentsCount += SHOW_COMMENTS_STEP; }; const showComments = (comments) => { commentsList.innerHTML = ''; currentComments = comments; - pictureShownComments.textContent = currentCommentsCount + SHOW_COMMENTS_STEP; - pictureTotalComments.textContent = comments.length; + imageShownComments.textContent = currentCommentsCount + SHOW_COMMENTS_STEP; + imageTotalComments.textContent = comments.length; showNextComments(); commentsShowMoreButton.addEventListener('click', showNextComments); }; diff --git a/js/image-filtration.js b/js/image-filtration.js index 9886418..c80f5ef 100644 --- a/js/image-filtration.js +++ b/js/image-filtration.js @@ -1,32 +1,32 @@ -import { renderPictures } from './pictures-preview-loader.js'; +import { renderImages } from './images-preview-loader.js'; import { getRandomInteger } from './util.js'; -const RANDOM_PHOTOS_COUNT = 10; +const RANDOM_IMAGES_COUNT = 10; const RERENDER_DELAY = 500; -const picturesFilter = document.querySelector('.img-filters'); +const imagesFilter = document.querySelector('.img-filters'); const FilterButtons = { - default: picturesFilter.querySelector('#filter-default'), - random: picturesFilter.querySelector('#filter-random'), - discussed: picturesFilter.querySelector('#filter-discussed'), + default: imagesFilter.querySelector('#filter-default'), + random: imagesFilter.querySelector('#filter-random'), + discussed: imagesFilter.querySelector('#filter-discussed'), }; -const compareCommentsCount = (photoA, photoB) => { - const commentsA = photoA.comments.length; - const commentsB = photoB.comments.length; +const compareCommentsCount = (imageA, imageB) => { + const commentsA = imageA.comments.length; + const commentsB = imageB.comments.length; return commentsB - commentsA; }; -const showFilter = () => picturesFilter.classList.remove('img-filters--inactive'); +const showFilter = () => imagesFilter.classList.remove('img-filters--inactive'); -const renderRandomPhotos = (photos) => { - const randomPhotos = photos.slice().sort(() => getRandomInteger(-1, 1)).splice(0, RANDOM_PHOTOS_COUNT); - renderPictures(randomPhotos); +const renderRandomImages = (images) => { + const randomImages = images.slice().sort(() => getRandomInteger(-1, 1)).splice(0, RANDOM_IMAGES_COUNT); + renderImages(randomImages); }; -const renderMostDiscussedPhotos = (photos) => { - const sortedPhotos = photos.slice().sort(compareCommentsCount); - renderPictures(sortedPhotos); +const renderMostDiscussedImages = (images) => { + const sortedImages = images.slice().sort(compareCommentsCount); + renderImages(sortedImages); }; const debounceRender = (renderFunction) => { @@ -36,8 +36,8 @@ const debounceRender = (renderFunction) => { }, RERENDER_DELAY); }; -const setFilterClickHandler = (photos) => { - picturesFilter.addEventListener('click', (evt) => { +const setFilterClickHandler = (images) => { + imagesFilter.addEventListener('click', (evt) => { const activeFilter = document.querySelector('.img-filters__button--active'); if (evt.target === activeFilter && evt.target !== FilterButtons.random) { @@ -51,15 +51,15 @@ const setFilterClickHandler = (photos) => { switch (evt.target) { case FilterButtons.default: - debounceRender(() => renderPictures(photos)); + debounceRender(() => renderImages(images)); break; case FilterButtons.random: - debounceRender(() => renderRandomPhotos(photos)); + debounceRender(() => renderRandomImages(images)); break; case FilterButtons.discussed: - debounceRender(() => renderMostDiscussedPhotos(photos)); + debounceRender(() => renderMostDiscussedImages(images)); break; } }); diff --git a/js/images-preview-loader.js b/js/images-preview-loader.js new file mode 100644 index 0000000..7a5c942 --- /dev/null +++ b/js/images-preview-loader.js @@ -0,0 +1,46 @@ +import { openImagePopup } from './show-image-fullscreen.js'; + +const imagesFragment = document.createDocumentFragment(); +const imagesContainer = document.querySelector('.pictures'); +const imageTemplate = document.querySelector('#picture').content.querySelector('.picture'); + +/** +* Отображает превью изображений на странице. +* @param {Array} usersImages - Массив объектов с данными изображений. +*/ + +const renderImages = (usersImages) => { + const existingImages = imagesContainer.querySelectorAll('.picture'); + existingImages.forEach((picture) => picture.remove()); + + usersImages.forEach(({ id, url, description, likes, comments }) => { + const imageElement = imageTemplate.cloneNode(true); + + imageElement.dataset.id = id; + imageElement.querySelector('.picture__img').src = url; + imageElement.querySelector('.picture__img').alt = description; + imageElement.querySelector('.picture__likes').textContent = likes; + imageElement.querySelector('.picture__comments').textContent = comments.length; + + imagesFragment.appendChild(imageElement); + }); + + imagesContainer.appendChild(imagesFragment); +}; + +const setImagesContainerClickHandler = (images) => { + imagesContainer.addEventListener('click', (evt) => { + const currentImageNode = evt.target.closest('.picture'); + if (currentImageNode){ + const currentImageNodeId = currentImageNode.dataset.id; + + const currentImageObject = images.find((image) => image.id === Number(currentImageNodeId)); + + if (currentImageObject) { + openImagePopup(currentImageObject); + } + } + }); +}; + +export { imagesContainer, renderImages, setImagesContainerClickHandler }; diff --git a/js/main.js b/js/main.js index 5fc60e5..e5354f1 100644 --- a/js/main.js +++ b/js/main.js @@ -1,4 +1,4 @@ -import { renderPictures, setPicturesContainerClickHandler } from './pictures-preview-loader.js'; +import { renderImages, setImagesContainerClickHandler } from './images-preview-loader.js'; import { loadData, showError } from './api.js'; import { initForm } from './image-upload.js'; import { showFilter, setFilterClickHandler } from './image-filtration.js'; @@ -12,11 +12,11 @@ import './image-filtration.js'; const init = async () => { try { - const picturesData = await loadData(); - renderPictures(picturesData); - setPicturesContainerClickHandler(picturesData); + const imagesData = await loadData(); + renderImages(imagesData); + setImagesContainerClickHandler(imagesData); showFilter(); - setFilterClickHandler(picturesData); + setFilterClickHandler(imagesData); } catch { showError(); } diff --git a/js/pictures-preview-loader.js b/js/pictures-preview-loader.js deleted file mode 100644 index 09788c1..0000000 --- a/js/pictures-preview-loader.js +++ /dev/null @@ -1,44 +0,0 @@ -import { openPicturePopup } from './show-image-fullscreen.js'; - -const picturesFragment = document.createDocumentFragment(); -const picturesContainer = document.querySelector('.pictures'); -const pictureTemplate = document.querySelector('#picture').content.querySelector('.picture'); - -/** -* Отображает превью изображений на странице. -* @param {Array} usersPictures - Массив объектов с данными изображений. -*/ - -const renderPictures = (usersPictures) => { - const existingPictures = picturesContainer.querySelectorAll('.picture'); - existingPictures.forEach((picture) => picture.remove()); - - usersPictures.forEach(({ id, url, description, likes, comments }) => { - const pictureElement = pictureTemplate.cloneNode(true); - - pictureElement.dataset.id = id; - pictureElement.querySelector('.picture__img').src = url; - pictureElement.querySelector('.picture__img').alt = description; - pictureElement.querySelector('.picture__likes').textContent = likes; - pictureElement.querySelector('.picture__comments').textContent = comments.length; - - picturesFragment.appendChild(pictureElement); - }); - - picturesContainer.appendChild(picturesFragment); -}; - -const setPicturesContainerClickHandler = (pictures) => { - picturesContainer.addEventListener('click', (evt) => { - const currentPictureNode = evt.target.closest('.picture'); - const currentPictureNodeId = currentPictureNode.dataset.id; - - const currentPicture = pictures.find((picture) => picture.id === Number(currentPictureNodeId)); - - if (currentPicture) { - openPicturePopup(currentPicture); - } - }); -}; - -export { picturesContainer, renderPictures, setPicturesContainerClickHandler }; diff --git a/js/show-image-fullscreen.js b/js/show-image-fullscreen.js index d10e82f..efa8fbf 100644 --- a/js/show-image-fullscreen.js +++ b/js/show-image-fullscreen.js @@ -1,46 +1,46 @@ import { isEscapeKey } from './util.js'; import { showComments, clearComments } from './comments-loader.js'; -const picture = document.querySelector('.big-picture'); -const pictureLikesCount = document.querySelector('.likes-count'); -const pictureCloseButton = document.querySelector('#picture-cancel'); -const pictureDescription = document.querySelector('.social__caption'); +const image = document.querySelector('.big-picture'); +const imageLikesCount = document.querySelector('.likes-count'); +const imageCloseButton = document.querySelector('#picture-cancel'); +const imageDescription = document.querySelector('.social__caption'); const documentKeydownHandler = (evt) => { if (isEscapeKey(evt)) { evt.preventDefault(); - closePicturePopup(); + closeImagePopup(); document.removeEventListener('keydown', documentKeydownHandler); clearComments(); } }; -function closePicturePopup() { +function closeImagePopup() { document.body.classList.remove('modal-open'); - picture.classList.add('hidden'); + image.classList.add('hidden'); clearComments(); - pictureCloseButton.removeEventListener('click', closePicturePopup); + imageCloseButton.removeEventListener('click', closeImagePopup); document.removeEventListener('keydown', documentKeydownHandler); } -const openPicturePopup = (pictureData) => { +const openImagePopup = (imageData) => { document.body.classList.add('modal-open'); - picture.classList.remove('hidden'); + image.classList.remove('hidden'); - picture.querySelector('img').src = pictureData.url; - pictureLikesCount.textContent = pictureData.likes; - pictureDescription.textContent = pictureData.description; - pictureCloseButton.addEventListener('click', closePicturePopup); + image.querySelector('img').src = imageData.url; + imageLikesCount.textContent = imageData.likes; + imageDescription.textContent = imageData.description; + imageCloseButton.addEventListener('click', closeImagePopup); - showComments(pictureData.comments); + showComments(imageData.comments); document.addEventListener('keydown', documentKeydownHandler); }; -export { openPicturePopup }; +export { openImagePopup }; From 430721b86effb1e81fefb1ce75aeb8fdc88f0fae Mon Sep 17 00:00:00 2001 From: Vladimir Gankin Date: Tue, 25 Mar 2025 18:20:16 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D1=8B=D0=B2=D0=B0=D0=B5=D1=82=20=D0=B7=D0=B0=D0=B4=D0=B5=D1=80?= =?UTF-8?q?=D0=B6=D0=BA=D1=83=20=D0=BF=D1=80=D0=B8=D0=BC=D0=B5=D0=BD=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D1=84=D0=B8=D0=BB=D1=8C=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B2=20=D0=B4=D0=BB=D1=8F=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB?= =?UTF-8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=BE=D0=B1?= =?UTF-8?q?=D1=89=D0=B5=D0=B9=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D0=B8?= =?UTF-8?q?=20=D0=B8=D0=B7=20util?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/image-filtration.js | 46 +++++++++++++++++++++++++++++------------- js/util.js | 12 ++++++++++- 2 files changed, 43 insertions(+), 15 deletions(-) diff --git a/js/image-filtration.js b/js/image-filtration.js index c80f5ef..cb5ebd6 100644 --- a/js/image-filtration.js +++ b/js/image-filtration.js @@ -1,5 +1,5 @@ import { renderImages } from './images-preview-loader.js'; -import { getRandomInteger } from './util.js'; +import { getRandomInteger, debounce } from './util.js'; const RANDOM_IMAGES_COUNT = 10; const RERENDER_DELAY = 500; @@ -21,22 +21,37 @@ const compareCommentsCount = (imageA, imageB) => { const showFilter = () => imagesFilter.classList.remove('img-filters--inactive'); const renderRandomImages = (images) => { - const randomImages = images.slice().sort(() => getRandomInteger(-1, 1)).splice(0, RANDOM_IMAGES_COUNT); + const randomImages = images + .slice() + .sort(() => getRandomInteger(-1, 1)) + .splice(0, RANDOM_IMAGES_COUNT); renderImages(randomImages); }; const renderMostDiscussedImages = (images) => { - const sortedImages = images.slice().sort(compareCommentsCount); + const sortedImages = images + .slice() + .sort(compareCommentsCount); renderImages(sortedImages); }; -const debounceRender = (renderFunction) => { - clearTimeout(debounceRender.lastDebouncedCall); - debounceRender.lastDebouncedCall = setTimeout(() => { - renderFunction(); - }, RERENDER_DELAY); -}; - const setFilterClickHandler = (images) => { + + const applyFilter = (selectedFilter) => { + switch (selectedFilter) { + case 'defaultFilter': + renderImages(images); + break; + case 'random': + renderRandomImages(images); + break; + case 'discussed': + renderMostDiscussedImages(images); + break; + } + }; + + const debouncedApplyFilter = debounce(applyFilter, RERENDER_DELAY); + imagesFilter.addEventListener('click', (evt) => { const activeFilter = document.querySelector('.img-filters__button--active'); @@ -49,21 +64,24 @@ const setFilterClickHandler = (images) => { evt.target.classList.add('img-filters__button--active'); } + let selectedFilter; + switch (evt.target) { case FilterButtons.default: - debounceRender(() => renderImages(images)); + selectedFilter = 'defaultFilter'; break; case FilterButtons.random: - debounceRender(() => renderRandomImages(images)); + selectedFilter = 'random'; break; case FilterButtons.discussed: - debounceRender(() => renderMostDiscussedImages(images)); + selectedFilter = 'discussed'; break; } + + debouncedApplyFilter(selectedFilter); }); }; - export { showFilter, setFilterClickHandler }; diff --git a/js/util.js b/js/util.js index 0b8ed13..b1e564d 100644 --- a/js/util.js +++ b/js/util.js @@ -5,4 +5,14 @@ const getRandomInteger = function(min, max) { const isEscapeKey = (evt) => evt.key === 'Escape'; -export { getRandomInteger, isEscapeKey }; +const debounce = (callback, delayMS = 500) => { + let timeoutId; + + return (...rest) => { + clearTimeout(timeoutId); + + timeoutId = setTimeout(() => callback.apply(this, rest), delayMS); + }; +}; + +export { getRandomInteger, isEscapeKey, debounce };