From 8f81c305fca985b30e8841e502c6ae13a440e8de Mon Sep 17 00:00:00 2001 From: "rit1992@mail.ru" <158091165+margarita0206@users.noreply.github.com> Date: Wed, 24 Jul 2024 15:09:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D0=BC=20=D1=8D=D1=84=D1=84=D0=B5=D0=BA=D1=82=D1=8B=20?= =?UTF-8?q?=D1=84=D0=BE=D1=82=D0=BE=20=D0=B8=20=D1=81=D0=BB=D0=B0=D0=B9?= =?UTF-8?q?=D0=B4=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.html | 2 + js/constant.js | 80 +++++++++++++++- js/effects-img.js | 95 +++++++++++++++++++ ...img-upload-form-modal.js => form-modal.js} | 18 ++-- js/form-validate.js | 75 +++++++++++++++ js/img-upload-form-validate.js | 10 -- js/main.js | 2 + js/modal-pictures.js | 4 +- js/scale.js | 35 +++++++ 9 files changed, 301 insertions(+), 20 deletions(-) create mode 100644 js/effects-img.js rename js/{img-upload-form-modal.js => form-modal.js} (78%) create mode 100644 js/form-validate.js delete mode 100644 js/img-upload-form-validate.js create mode 100644 js/scale.js diff --git a/index.html b/index.html index b6029b7..65fdd3a 100644 --- a/index.html +++ b/index.html @@ -5,6 +5,7 @@ + Кекстаграм @@ -236,5 +237,6 @@

Не удалось загрузить данны + diff --git a/js/constant.js b/js/constant.js index b6d25af..470e45c 100644 --- a/js/constant.js +++ b/js/constant.js @@ -8,6 +8,81 @@ export const COMMENT_MIN_COUNT = 0; export const COMMENT_MAX_COUNT = 30; export const COMMENT_MAX_ID = 500000; +export const HASHTAG_CHECK = /^#[a-zа-яё0-9]{1,19}$/i; +export const SPACE = /\s+/g; +export const MAX_HASHTAG = 5; +export const MAX_MESSAGE_LENGTH = 140; + +export const SCALE_STEP = 25; +export const MIN_SCALE = 25; +export const MAX_SCALE = 100; +export const DEFAULT_SCALE = 100; + +const EFFECT = { + DEFAULT: 'none', + CHROME: 'chrome', + SEPIA: 'sepia', + MARVIN: 'marvin', + PHOBOS: 'phobos', + HEAT: 'heat', +}; + +const EFFECT_TO_FILTER = { + [EFFECT.CHROME]: { + style: 'grayscale', + unit: '', + }, + [EFFECT.SEPIA]: { + style: 'sepia', + unit: '', + }, + [EFFECT.MARVIN]: { + style: 'invert', + unit: '%', + }, + [EFFECT.PHOBOS]: { + style: 'blur', + unit: 'px', + }, + [EFFECT.HEAT]: { + style: 'brightness', + unit: '', + }, +}; + +const EFFECT_TO_SLIDER_OPTIONS = { + [EFFECT.DEFAULT]: { + min: 0, + max: 100, + step: 1, + }, + [EFFECT.CHROME]: { + min: 0, + max: 1, + step: 0.1, + }, + [EFFECT.SEPIA]: { + min: 0, + max: 1, + step: 0.1, + }, + [EFFECT.MARVIN]: { + min: 0, + max: 100, + step: 1, + }, + [EFFECT.PHOBOS]: { + min: 0, + max: 3, + step: 0.1, + }, + [EFFECT.HEAT]: { + min: 1, + max: 3, + step: 0.1, + }, +}; + const COMMENT_NAMES = [ 'Анна', 'Александр', @@ -55,5 +130,8 @@ const DESCRIPTIONS = [ export { COMMENT_NAMES, POSTS_COMMENTS, - DESCRIPTIONS + DESCRIPTIONS, + EFFECT, + EFFECT_TO_FILTER, + EFFECT_TO_SLIDER_OPTIONS }; diff --git a/js/effects-img.js b/js/effects-img.js new file mode 100644 index 0000000..3fe7848 --- /dev/null +++ b/js/effects-img.js @@ -0,0 +1,95 @@ +import { + EFFECT, + EFFECT_TO_FILTER, + EFFECT_TO_SLIDER_OPTIONS +} from './constant.js'; + +const modalElement = document.querySelector('.img-upload'); +const imgElement = modalElement.querySelector('.img-upload__preview'); +const effectsElement = modalElement.querySelector('.effects'); +const slider = modalElement.querySelector('.effect-level__slider'); +const sliderContainer = modalElement.querySelector('.img-upload__effect-level'); + +const effectLevelElement = modalElement.querySelector('.effect-level__value'); + +let chosenEffect = EFFECT.DEFAULT; + +const isDefault = () => chosenEffect === EFFECT.DEFAULT; + +const setImageStyle = () => { + if (isDefault()) { + imgElement.style.filter = null; + return; + } + + const { value } = effectLevelElement; + const { style, unit } = EFFECT_TO_FILTER[chosenEffect]; + imgElement.style.filter = `${style}(${value}${unit})`; +}; + +const showSlider = () => { + sliderContainer.classList.remove('hidden'); +}; + +const hideSlider = () => { + sliderContainer.classList.add('hidden'); +}; + +const onSliderUpdate = () => { + effectLevelElement.value = slider.noUiSlider.get(); + setImageStyle(); +}; + +const createSlider = ({ min, max, step }) => { + noUiSlider.create(slider, { + range: { min, max }, + step, + start: max, + connect: 'lower', + format: { + to: (value) => Number(value), + from: (value) => Number(value), + } + }); + + slider.noUiSlider.on('update', onSliderUpdate); + hideSlider(); +}; + +const updateSlider = ({ min, max, step }) => { + slider.noUiSlider.updateOptions({ + range: { min, max }, + step, + start: max, + }); +}; + +const setSlider = () => { + if (isDefault()) { + hideSlider(); + } else { + updateSlider(EFFECT_TO_SLIDER_OPTIONS[chosenEffect]); + showSlider(); + } +}; + +const setEffect = (effect) => { + chosenEffect = effect; + setSlider(); + setImageStyle(); +}; + +const reset = () => { + setEffect(EFFECT.DEFAULT); +}; + +const onEffectsChange = (evt) => { + setEffect(evt.target.value); +}; + +const init = () => { + createSlider(EFFECT_TO_SLIDER_OPTIONS[chosenEffect]); + effectsElement.addEventListener('change', onEffectsChange); +}; + +export { init, reset }; diff --git a/js/img-upload-form-modal.js b/js/form-modal.js similarity index 78% rename from js/img-upload-form-modal.js rename to js/form-modal.js index bc812bd..da0d28c 100644 --- a/js/img-upload-form-modal.js +++ b/js/form-modal.js @@ -1,5 +1,9 @@ -import { isValid } from './img-upload-form-validate'; -import { isEscapeKey } from './utils'; +import { isValid } from './form-validate.js'; +import { isEscapeKey } from './utils.js'; +import { resetScale } from './scale.js'; +import { + reset as resetEffect +} from './effects-img.js'; const imgUploadform = document.querySelector('.img-upload__form'); const redactForm = document.querySelector('.img-upload__overlay'); @@ -8,16 +12,17 @@ const imgUploadCancelButton = document.querySelector('.img-upload__cancel'); const fieldComments = document.querySelector('.text__description'); const fieldHashtag = document.querySelector('.text__hashtags'); - const openRedactForm = () => { redactForm.classList.remove('hidden'); - document.body.classList.add('.modal-open'); + document.body.classList.add('modal-open'); document.addEventListener('keydown', onDocumentKeydown); }; const closeRedactForm = () => { - redactForm.classList.add('.hidden'); - document.body.classList.remove('.modal-open'); + resetScale(); + resetEffect(); + redactForm.classList.add('hidden'); + document.body.classList.remove('modal-open'); imgUploadInput.value = ''; document.removeEventListener('keydown', onDocumentKeydown); }; @@ -54,4 +59,3 @@ imgUploadform.addEventListener('submit', (evt) => { evt.preventDefault(); } }); - diff --git a/js/form-validate.js b/js/form-validate.js new file mode 100644 index 0000000..6c89820 --- /dev/null +++ b/js/form-validate.js @@ -0,0 +1,75 @@ +import { + HASHTAG_CHECK, + SPACE, + MAX_HASHTAG, + MAX_MESSAGE_LENGTH +} from './constant.js'; + +import { + init as initEffect +} from './effects-img.js'; + +const imgUploadform = document.querySelector('.img-upload__form'); +const fieldComments = imgUploadform.querySelector('.text__description'); +const fieldHashtag = imgUploadform.querySelector('.text__hashtags'); + +const pristine = new Pristine(imgUploadform, { + classTo: 'img-upload__field-wrapper', + errorTextParent: 'img-upload__field-wrapper', + errorTextClass: 'img-upload__field-wrapper__error' +}); + +const normalizeHashtage = (value) => !value.length ? [] : fieldHashtag.value.toLowerCase().replaceAll(SPACE, ' ').trim().split(' '); + +const validateFormatHashtag = (value) => { + const hashes = normalizeHashtage(value); + return hashes.every((hashtag) => HASHTAG_CHECK.test(hashtag)); +}; + +const checkUnique = (value) => { + const hashes = normalizeHashtage(value); + const uniques = [...new Set(hashes)]; + return hashes.length === uniques.length; +}; + +const checkCount = (value) => { + const hashes = normalizeHashtage(value); + return hashes.length <= MAX_HASHTAG; +}; + +pristine.addValidator( + fieldHashtag, + validateFormatHashtag, + 'Неверный формат', + 1, + true +); + +pristine.addValidator( + fieldHashtag, + checkUnique, + 'Хэштег должен быть уникальным!', + 2, + true +); + +pristine.addValidator( + fieldHashtag, + checkCount, + 'Допустимое количество хэштегов - 5', + 3, + true +); + +const validateComment = () => fieldComments.value.length <= MAX_MESSAGE_LENGTH; + +pristine.addValidator( + fieldComments, + validateComment, + `Длина комментария не может превышать ${MAX_MESSAGE_LENGTH} символов` +); + +const isValid = () => pristine.validate(); +initEffect(); + +export { isValid }; diff --git a/js/img-upload-form-validate.js b/js/img-upload-form-validate.js deleted file mode 100644 index cde072a..0000000 --- a/js/img-upload-form-validate.js +++ /dev/null @@ -1,10 +0,0 @@ -const orderForm = document.querySelector('.img-upload__form'); - -const pristine = new Pristine(orderForm, { - classTo: 'form__item', - errorClass: 'form__item--invalid', - successClass: 'form__item--valid', - errorTextParent: 'form__item', - errorTextTag: 'span', - errorTextClass: 'form__error' -}); diff --git a/js/main.js b/js/main.js index 6050cb2..803ad65 100644 --- a/js/main.js +++ b/js/main.js @@ -1,6 +1,8 @@ import {randomPosts} from './data.js'; import {generateThumbnails} from './thumbnail.js'; import './modal-pictures.js'; +import './form-modal.js'; +import './form-validate.js'; const currentPictures = randomPosts(); diff --git a/js/modal-pictures.js b/js/modal-pictures.js index b1710fb..2887bfb 100644 --- a/js/modal-pictures.js +++ b/js/modal-pictures.js @@ -66,14 +66,14 @@ const onDocumentKeydown = (evt) => { const openBigPictureWindow = (photo) => { bigPicturesModal.classList.remove('hidden'); - body.classList.add('.modal-open'); + body.classList.add('modal-open'); document.addEventListener('keydown', onDocumentKeydown); fillDataBigPicture(photo); }; const closeBigPictureWindow = () => { bigPicturesModal.classList.add('hidden'); - body.classList.remove('.modal-open'); + body.classList.remove('modal-open'); document.removeEventListener('keydown', onDocumentKeydown); }; diff --git a/js/scale.js b/js/scale.js new file mode 100644 index 0000000..4b97d7d --- /dev/null +++ b/js/scale.js @@ -0,0 +1,35 @@ +import { + SCALE_STEP, + MIN_SCALE, + MAX_SCALE, + DEFAULT_SCALE +} from './constant.js'; + +const scaleInput = document.querySelector('.scale__control--value'); +const smallButtonElement = document.querySelector('.scale__control--smaller'); +const bigButtonElement = document.querySelector('.scale__control--bigger'); +const imgPreviewElement = document.querySelector('.img-upload__preview img'); + +const scaleImage = (value) => { + imgPreviewElement.style.transform = `scale(${value / 100})`; + scaleInput.value = `${value}%`; +}; + +const onSmallerClickButton = () => { + scaleImage( + Math.max(parseInt(scaleInput.value, 10) - SCALE_STEP, MIN_SCALE) + ); +}; + +const onBiggerClickButton = () => { + scaleImage( + Math.min(parseInt(scaleInput.value, 10) + SCALE_STEP, MAX_SCALE) + ); +}; + +const resetScale = () => scaleImage(DEFAULT_SCALE); + +smallButtonElement.addEventListener('click', onSmallerClickButton); +bigButtonElement.addEventListener('click', onBiggerClickButton); + +export { resetScale };