From f0fa92e8b6dfed150b67288e1925527c925d6ab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Sun, 5 Jan 2025 09:21:15 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D0=94=D0=9710?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/form.js | 2 + js/functions.js | 17 ------ js/image-editor.js | 135 +++++++++++++++++++++++++++++++++++++++++++++ js/main.js | 1 + js/photo-modal.js | 58 ++++++++++--------- js/thumbnails.js | 12 ++-- js/validator.js | 10 ++-- 7 files changed, 180 insertions(+), 55 deletions(-) delete mode 100644 js/functions.js create mode 100644 js/image-editor.js diff --git a/js/form.js b/js/form.js index 5196362..c8cc5c0 100644 --- a/js/form.js +++ b/js/form.js @@ -1,5 +1,6 @@ import { isEscapeKey } from './util.js'; import { runValidator, stopValidator } from './validator.js'; +import { runImageEditor } from './image-editor.js'; const imgUploadElement = document.querySelector('.img-upload__input'); const imgEditElement = document.querySelector('.img-upload__overlay'); @@ -11,6 +12,7 @@ const newHashTagsElement = document.querySelector('.text__hashtags'); const setupFormEventListeners = () => { imgUploadElement.addEventListener('change', () => { runValidator(); + runImageEditor(); imgEditElement.classList.remove('hidden'); bodyContainerElement.classList.add('modal-open'); imgEditCloseButtonElement.addEventListener('click', onClickCloseButton); diff --git a/js/functions.js b/js/functions.js deleted file mode 100644 index d61e753..0000000 --- a/js/functions.js +++ /dev/null @@ -1,17 +0,0 @@ -// const isWithinWorkingHours = (workdayStart, workdayEnd, meetingStart, meetingLength) => { -// const convertToMinutes = (timeString) => { -// const [hours, minutes] = timeString.split(':'); -// return (Number(hours) * 60) + Number(minutes) -// }; -// const workdayStartMinutes = convertToMinutes(workdayStart); -// const workdayEndMinutes = convertToMinutes(workdayEnd); -// const meetingStartMinutes = convertToMinutes(meetingStart); -// const meetingEndMinutes = meetingStartMinutes + meetingLength; -// return meetingStartMinutes >= workdayStartMinutes && meetingEndMinutes <= workdayEndMinutes -// }; - -// console.log(isWithinWorkingHours('08:00', '17:30', '14:00', 90)); -// console.log(isWithinWorkingHours('8:0', '10:0', '8:0', 120)); -// console.log(isWithinWorkingHours('08:00', '14:30', '14:00', 90)); -// console.log(isWithinWorkingHours('14:00', '17:30', '08:0', 90)); -// console.log(isWithinWorkingHours('8:00', '17:30', '08:00', 900)); diff --git a/js/image-editor.js b/js/image-editor.js new file mode 100644 index 0000000..daa96aa --- /dev/null +++ b/js/image-editor.js @@ -0,0 +1,135 @@ +import '../vendor/nouislider/nouislider.js'; +import '../vendor/nouislider/nouislider.css'; + +const buttonDecrementElement = document.querySelector('.scale__control--smaller'); +const buttonIncrementElement = document.querySelector('.scale__control--bigger'); +const scaleValueElement = document.querySelector('.scale__control--value'); + +const sliderContainerElement = document.querySelector('.img-upload__effect-level'); +const sliderElement = sliderContainerElement.querySelector('.effect-level__slider'); +const effectLevelElement = sliderContainerElement.querySelector('.effect-level__value'); +const ImageElement = document.querySelector('.img-upload__preview'); +const effectListElement = document.querySelector('.effects__list'); +const originalElement = effectListElement.querySelector('#effect-none'); + +const SCALE = { + MIN: 0.25, + MAX: 1, + STEP: 0.25, + DEFAULT: 1, +}; + +const EFFECTS = { + chrome: { + MIN: 0, + MAX: 1, + START: 1, + STEP: 0.1, + STYLE: 'grayscale', + UNIT: '', + }, + sepia: { + MIN: 0, + MAX: 1, + START: 1, + STEP: 0.1, + STYLE: 'sepia', + UNIT: '', + }, + marvin: { + MIN: 0, + MAX: 100, + START: 100, + STEP: 1, + STYLE: 'invert', + UNIT: '%', + }, + phobos: { + MIN: 0, + MAX: 3, + START: 3, + STEP: 0.1, + STYLE: 'blur', + UNIT: 'px', + }, + heat: { + MIN: 0, + MAX: 3, + START: 3, + STEP: 0.1, + STYLE: 'brightness', + UNIT: '', + }, +}; + + +// Создаем редактирование масштаба +let scaleValue = SCALE.DEFAULT; + +const formatScale = (value) => `${value * 100}%`; + +const changeScale = (value) => { + scaleValue = value; + ImageElement.style.transform = `scale(${scaleValue})`; + scaleValueElement.value = formatScale(scaleValue); +}; + +const decrementScale = () => { + if (scaleValue > SCALE.MIN) { + changeScale(scaleValue - SCALE.STEP); + } +}; + +const incrementScale = () => { + if (scaleValue < SCALE.MAX) { + changeScale(scaleValue + SCALE.STEP); + } +}; + +// Создаем слайдер +const createSlider = ({ MIN, MAX, START, STEP, STYLE, UNIT }) => { + noUiSlider.create(sliderElement, { + range: { min: MIN, max: MAX }, + start: START, + step: STEP, + connect: 'lower', + format: { + to: (value) => value.toFixed(1), + from: (value) => parseFloat(value) + } + }); + + sliderElement.noUiSlider.on('update', () => { + const value = sliderElement.noUiSlider.get(); + effectLevelElement.value = value; + ImageElement.style.filter = `${STYLE}(${value}${UNIT})`; + }); +}; + +const addEffect = () => { + if (sliderElement.noUiSlider) { + sliderElement.noUiSlider.destroy(); + } + if (originalElement.checked) { + ImageElement.style.filter = 'none'; + sliderContainerElement.classList.add('hidden'); + return; + } + sliderContainerElement.classList.remove('hidden'); + + const checkedEffect = effectListElement.querySelector('input:checked').value; + createSlider(EFFECTS[checkedEffect]); +}; + +const runImageEditor = () => { + ImageElement.style.filter = 'none'; + sliderContainerElement.classList.add('hidden'); + effectListElement.addEventListener('change', addEffect); + scaleValue = SCALE.DEFAULT; + ImageElement.style.transform = `scale(${SCALE.DEFAULT})`; + scaleValueElement.value = formatScale(scaleValue); + buttonDecrementElement.addEventListener('click', decrementScale); + buttonIncrementElement.addEventListener('click', incrementScale); +}; + +export { runImageEditor }; diff --git a/js/main.js b/js/main.js index 3d4068a..3cac2a5 100644 --- a/js/main.js +++ b/js/main.js @@ -7,3 +7,4 @@ const photoCollection = generateArrObj(); renderGallery(photoCollection); setupPictureEventListeners(photoCollection); setupFormEventListeners(); + diff --git a/js/photo-modal.js b/js/photo-modal.js index 9ab7206..8fcbabf 100644 --- a/js/photo-modal.js +++ b/js/photo-modal.js @@ -2,42 +2,42 @@ import { isEscapeKey } from './util.js'; import { initComments } from './comments-loader.js'; // Общий контейнер -const bodyContainerElement = document.body; +const body = document.body; // Контейнер с картинками const picturesContainerElement = document.querySelector('.pictures'); // Элементы большой картинки -const bigPictureContainerElement = document.querySelector('.big-picture'); -const bigPictureOverlayElement = document.querySelector('.overlay'); -const bigPictureCloseButtonElement = bigPictureContainerElement.querySelector('.big-picture__cancel'); -const bigPictureImageElement = bigPictureContainerElement.querySelector('.big-picture__img img'); -const bigPictureSocialElement = bigPictureContainerElement.querySelector('.big-picture__social'); -const bigPictureLikesElement = bigPictureSocialElement.querySelector('.likes-count'); -const bigPictureDescriptionElement = bigPictureSocialElement.querySelector('.social__caption'); +const ContainerElement = document.querySelector('.big-picture'); +const OverlayElement = document.querySelector('.overlay'); +const CloseButtonElement = ContainerElement.querySelector('.big-picture__cancel'); +const ImageElement = ContainerElement.querySelector('.big-picture__img img'); +const SocialElement = ContainerElement.querySelector('.big-picture__social'); +const LikesElement = SocialElement.querySelector('.likes-count'); +const DescriptionElement = SocialElement.querySelector('.social__caption'); // Рендер большой картинки -const renderBigPicture = ({ url, likes, comments, description }) => { - bigPictureImageElement.src = url; - bigPictureLikesElement.textContent = likes; - bigPictureDescriptionElement.textContent = description; - bigPictureCloseButtonElement.addEventListener('click', onClickCloseButton); - bigPictureOverlayElement.addEventListener('click', onOverlayClick); +const render = ({ url, likes, comments, description }) => { + ImageElement.src = url; + LikesElement.textContent = likes; + DescriptionElement.textContent = description; + CloseButtonElement.addEventListener('click', onClickCloseButton); + OverlayElement.addEventListener('click', onOverlayClick); document.addEventListener('keydown', onKeydownDocument); initComments(comments); // Инициализируем комментарии - bigPictureContainerElement.classList.remove('hidden'); // включаем видимость контейнера большой картинки - bodyContainerElement.classList.add('modal-open'); // блокируем прокрутку body + ContainerElement.classList.remove('hidden'); // включаем видимость контейнера большой картинки + body.classList.add('modal-open'); // блокируем прокрутку body }; // Вызов закрытия картинки нажатием на закрывающий элемент function onClickCloseButton () { - closeBigPicture(); + close(); } // Вызов закрытия картинки нажатием мимо модального окна function onOverlayClick(evt) { - if (evt.target === bigPictureOverlayElement) { - closeBigPicture(); + if (evt.target === OverlayElement) { + close(); } } @@ -45,25 +45,29 @@ function onOverlayClick(evt) { function onKeydownDocument (evt) { if (isEscapeKey(evt)) { evt.preventDefault(); - closeBigPicture(); + close(); } } -function closeBigPicture () { - bigPictureCloseButtonElement.removeEventListener('click', onClickCloseButton); - bigPictureContainerElement.removeEventListener('click', onOverlayClick); +function close () { + CloseButtonElement.removeEventListener('click', onClickCloseButton); + ContainerElement.removeEventListener('click', onOverlayClick); document.removeEventListener('keydown', onKeydownDocument); - bigPictureContainerElement.classList.add('hidden'); - bodyContainerElement.classList.remove('modal-open'); + ContainerElement.classList.add('hidden'); + body.classList.remove('modal-open'); } // Функция добавления обработчика событий на контейнер с картинками и вычисление ID картинки, по которой был клик const setupPictureEventListeners = (photoCollection) => { picturesContainerElement.addEventListener('click', (evt) => { - const id = evt.target.closest('.picture').dataset.pictureId; // поиск по установленному атрибуту data-set-id + const target = evt.target.closest('.picture'); + if (!target) { + return; + } + const id = target.dataset.pictureId; // поиск по установленному атрибуту data-set-id if (id) { const foundedPhoto = photoCollection.find((picture) => picture.id === Number(id)); - renderBigPicture(foundedPhoto); + render(foundedPhoto); } }); }; diff --git a/js/thumbnails.js b/js/thumbnails.js index 349930b..2e1e2c3 100644 --- a/js/thumbnails.js +++ b/js/thumbnails.js @@ -1,19 +1,19 @@ const renderGallery = (userPictures) => { - const picturesContainer = document.querySelector('.pictures'); - const pictureTemplate = document.querySelector('#picture').content.querySelector('a'); + const picturesContainerElement = document.querySelector('.pictures'); + const pictureTemplateElement = document.querySelector('#picture').content.querySelector('a'); - const pictureFragment = document.createDocumentFragment(); + const pictureFragmentElement = document.createDocumentFragment(); userPictures.forEach(({id, url, description, likes, comments}) => { - const pictureElement = pictureTemplate.cloneNode(true); + const pictureElement = pictureTemplateElement.cloneNode(true); pictureElement.dataset.pictureId = id; // Устанавливает атрибут data-set-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; - pictureFragment.append(pictureElement); + pictureFragmentElement.append(pictureElement); }); - picturesContainer.append(pictureFragment); + picturesContainerElement.append(pictureFragmentElement); }; export { renderGallery }; diff --git a/js/validator.js b/js/validator.js index d879720..be01ebe 100644 --- a/js/validator.js +++ b/js/validator.js @@ -4,12 +4,12 @@ const MAX_LENGTH = 140; const MAX_QTY = 5; -const imgEditForm = document.querySelector('.img-upload__form'); -const newCommentElement = document.querySelector('.text__description'); -const newHashTagsElement = document.querySelector('.text__hashtags'); -const submitButtonElement = document.querySelector('.img-upload__submit'); +const imgEditFormElement = document.querySelector('.img-upload__form'); +const newCommentElement = imgEditFormElement.querySelector('.text__description'); +const newHashTagsElement = imgEditFormElement.querySelector('.text__hashtags'); +const submitButtonElement = imgEditFormElement.querySelector('.img-upload__submit'); -const pristine = new Pristine(imgEditForm, { +const pristine = new Pristine(imgEditFormElement, { classTo: 'img-upload__field-wrapper', errorClass: 'img-upload__field-wrapper--error', errorTextParent: 'img-upload__field-wrapper', From 9db5597e44815201f923e01910ac24c67d21ffe7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=BB=D0=B0=D0=B4?= Date: Mon, 13 Jan 2025 15:29:16 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=9F=D1=80=D0=B0=D0=B2=D0=BA=D0=B8=20?= =?UTF-8?q?=D0=BF=D0=BE=20=D0=BD=D0=B0=D0=B7=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F?= =?UTF-8?q?=D0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/photo-modal.js | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/js/photo-modal.js b/js/photo-modal.js index 8fcbabf..9bf168f 100644 --- a/js/photo-modal.js +++ b/js/photo-modal.js @@ -8,36 +8,36 @@ const body = document.body; const picturesContainerElement = document.querySelector('.pictures'); // Элементы большой картинки -const ContainerElement = document.querySelector('.big-picture'); -const OverlayElement = document.querySelector('.overlay'); -const CloseButtonElement = ContainerElement.querySelector('.big-picture__cancel'); -const ImageElement = ContainerElement.querySelector('.big-picture__img img'); -const SocialElement = ContainerElement.querySelector('.big-picture__social'); -const LikesElement = SocialElement.querySelector('.likes-count'); -const DescriptionElement = SocialElement.querySelector('.social__caption'); +const containerElement = document.querySelector('.big-picture'); +const overlayElement = document.querySelector('.overlay'); +const closeButtonElement = containerElement.querySelector('.big-picture__cancel'); +const imageElement = containerElement.querySelector('.big-picture__img img'); +const socialElement = containerElement.querySelector('.big-picture__social'); +const likesElement = socialElement.querySelector('.likes-count'); +const descriptionElement = socialElement.querySelector('.social__caption'); // Рендер большой картинки -const render = ({ url, likes, comments, description }) => { - ImageElement.src = url; - LikesElement.textContent = likes; - DescriptionElement.textContent = description; - CloseButtonElement.addEventListener('click', onClickCloseButton); - OverlayElement.addEventListener('click', onOverlayClick); +const renderBigPicture = ({ url, likes, comments, description }) => { + imageElement.src = url; + likesElement.textContent = likes; + descriptionElement.textContent = description; + closeButtonElement.addEventListener('click', onClickCloseButton); + overlayElement.addEventListener('click', onOverlayClick); document.addEventListener('keydown', onKeydownDocument); initComments(comments); // Инициализируем комментарии - ContainerElement.classList.remove('hidden'); // включаем видимость контейнера большой картинки + containerElement.classList.remove('hidden'); // включаем видимость контейнера большой картинки body.classList.add('modal-open'); // блокируем прокрутку body }; // Вызов закрытия картинки нажатием на закрывающий элемент function onClickCloseButton () { - close(); + closeBigPicture(); } // Вызов закрытия картинки нажатием мимо модального окна function onOverlayClick(evt) { - if (evt.target === OverlayElement) { - close(); + if (evt.target === overlayElement) { + closeBigPicture(); } } @@ -45,15 +45,15 @@ function onOverlayClick(evt) { function onKeydownDocument (evt) { if (isEscapeKey(evt)) { evt.preventDefault(); - close(); + closeBigPicture(); } } -function close () { - CloseButtonElement.removeEventListener('click', onClickCloseButton); - ContainerElement.removeEventListener('click', onOverlayClick); +function closeBigPicture () { + closeButtonElement.removeEventListener('click', onClickCloseButton); + containerElement.removeEventListener('click', onOverlayClick); document.removeEventListener('keydown', onKeydownDocument); - ContainerElement.classList.add('hidden'); + containerElement.classList.add('hidden'); body.classList.remove('modal-open'); } @@ -67,7 +67,7 @@ const setupPictureEventListeners = (photoCollection) => { const id = target.dataset.pictureId; // поиск по установленному атрибуту data-set-id if (id) { const foundedPhoto = photoCollection.find((picture) => picture.id === Number(id)); - render(foundedPhoto); + renderBigPicture(foundedPhoto); } }); };