diff --git a/index.html b/index.html index 8ba05e1..9562ed8 100644 --- a/index.html +++ b/index.html @@ -6,6 +6,7 @@ + Кекстаграм @@ -31,7 +32,7 @@

Фотографии других

Загрузка фотографии

-
+
@@ -40,7 +41,7 @@

Загрузка фотограф

-
+ + diff --git a/js/big-picture.js b/js/big-picture.js index 87ef0a9..a3e3e4e 100644 --- a/js/big-picture.js +++ b/js/big-picture.js @@ -21,16 +21,14 @@ let currentComments = []; const onEscKeyDown = (evt) => { if (isEscapeKey(evt)) { closeBigPicture(); - deleteComments(); } }; const onPictureCancelClick = () => { closeBigPicture(); - deleteComments(); }; -const renderNewCommentsStep = () => { +const onShowMoreButtonClick = () => { const renderingNewComments = currentComments.slice(commentCount, commentCount + COMMENTS__STEP); const newCommentsLength = renderingNewComments.length += commentCount; const fragment = document.createDocumentFragment(); @@ -57,17 +55,17 @@ const renderNewCommentsStep = () => { const renderComments = (currentPhotoComments) => { currentComments = currentPhotoComments; - renderNewCommentsStep(); + onShowMoreButtonClick(); - buttonLoader.addEventListener('click', renderNewCommentsStep); + buttonLoader.addEventListener('click', onShowMoreButtonClick); }; -function deleteComments () { +const deleteComments = () => { socialComments.innerHTML = ''; commentCount = 0; buttonLoader.classList.remove('hidden'); - buttonLoader.removeEventListener('click', renderNewCommentsStep); -} + buttonLoader.removeEventListener('click', onShowMoreButtonClick); +}; const renderBigPicture = (currentPhoto) => { bigPictureImage.src = currentPhoto.url; @@ -78,6 +76,8 @@ const renderBigPicture = (currentPhoto) => { }; function closeBigPicture () { + deleteComments(); + bigPicture.classList.add('hidden'); document.querySelector('body').classList.remove('modal-open'); document.removeEventListener('keydown', onEscKeyDown); @@ -111,5 +111,5 @@ const setPicturesListener = (photos) => { usersPhotoList.addEventListener('click', (evt) => onPictureContainerClick(evt, photos)); }; -export { setPicturesListener }; +export { setPicturesListener, onEscKeyDown }; diff --git a/js/form/image-form.js b/js/form/image-form.js new file mode 100644 index 0000000..adca43c --- /dev/null +++ b/js/form/image-form.js @@ -0,0 +1,51 @@ +import { isEscapeKey } from '../util'; +import { initScale, resetScale } from './image-scale'; +import { initValidation } from './validation'; +import { initEffect, resetEffect } from './slider-effect'; + +const uploadForm = document.querySelector('.img-upload__form'); +const uploadInput = uploadForm.querySelector('.img-upload__input'); +const formOverlay = uploadForm.querySelector('.img-upload__overlay'); +const buttonCloseUpload = uploadForm.querySelector('.img-upload__cancel'); +const hashtagsInput = uploadForm.querySelector('.text__hashtags'); +const descriptionInput = uploadForm.querySelector('.text__description'); + +const onEscKeyDown = (evt) => { + if (isEscapeKey(evt) && (document.activeElement !== hashtagsInput || document.activeElement !== descriptionInput)) { + closeUploadModal(); + uploadForm.reset(); + } +}; +const onUploadCancelClick = () => { + closeUploadModal(); +}; + +function closeUploadModal () { + formOverlay.classList.add('hidden'); + document.querySelector('body').classList.remove('.modal-open'); + document.removeEventListener('keydown', onEscKeyDown); + buttonCloseUpload.removeEventListener('click', onUploadCancelClick); + + resetEffect(); + resetScale(); + uploadForm.reset(); +} + +const openUploadModal = () =>{ + formOverlay.classList.remove('hidden'); + document.querySelector('body').classList.add('.modal-open'); + document.addEventListener('keydown', onEscKeyDown); + buttonCloseUpload.addEventListener('click', onUploadCancelClick); + + initEffect(); + initScale(); + initValidation(); +}; + +const initUploadModal = () => { + uploadInput.addEventListener('change', () => { + openUploadModal(); + }); +}; + +export { initUploadModal }; diff --git a/js/form/image-scale.js b/js/form/image-scale.js new file mode 100644 index 0000000..cd3ba75 --- /dev/null +++ b/js/form/image-scale.js @@ -0,0 +1,35 @@ +const scaleValue = document.querySelector('.scale__control--value'); +const imagePrewiev = document.querySelector('.img-upload__preview img'); +const buttonSmaller = document.querySelector('.scale__control--smaller'); +const buttonBigger = document.querySelector('.scale__control--bigger'); + +let scale = 1; +const SCALE_STEP = 0.25; + +const onButtonSmallerClick = () => { + if(scale > SCALE_STEP) { + scale -= SCALE_STEP; + imagePrewiev.style.transform = `scale(${scale})`; + scaleValue.value = `${scale * 100}%`; + } +}; + +const onButtonBiggerClick = () => { + if(scale < 1) { + scale += SCALE_STEP; + imagePrewiev.style.transform = `scale(${scale})`; + scaleValue.value = `${scale * 100}%`; + } +}; + +const initScale = () => { + buttonSmaller.addEventListener('click', onButtonSmallerClick); + buttonBigger.addEventListener('click', onButtonBiggerClick); +}; + +const resetScale = () => { + buttonBigger.removeEventListener('click', onButtonBiggerClick); + buttonSmaller.removeEventListener('click', onButtonSmallerClick); +}; + +export { initScale, resetScale }; diff --git a/js/form/slider-effect.js b/js/form/slider-effect.js new file mode 100644 index 0000000..4417248 --- /dev/null +++ b/js/form/slider-effect.js @@ -0,0 +1,72 @@ +import { SLIDER_EFFECT_OPTIONS } from './slider-options'; + +const sliderElement = document.querySelector('.effect-level__slider'); +const sliderContainer = document.querySelector('.img-upload__effect-level'); +const imagePreview = document.querySelector('.img-upload__preview img'); +const effectList = document.querySelector('.img-upload__effects'); +const sliderEffectValue = document.querySelector('.effect-level__value'); + +let currentEffect = 'none'; + +const updateSliderEffect = (effect) => { + if(effect === 'none') { + sliderContainer.style.display = 'none'; + imagePreview.style.filter = 'none'; + } else { + sliderContainer.style.display = 'block'; + } + + sliderElement.noUiSlider.on('update', () => { + const sliderValue = sliderElement.noUiSlider.get(); + sliderEffectValue.value = sliderValue; + + const configSlider = SLIDER_EFFECT_OPTIONS[currentEffect]; + if (currentEffect !== 'none') { + imagePreview.style.filter = `${configSlider.filter}(${sliderValue}${configSlider.measure})`; + } + }); +}; + +const changeSliderOptions = () => { + const configSlider = SLIDER_EFFECT_OPTIONS[currentEffect]; + + sliderElement.noUiSlider.updateOptions({ + range: { + min: configSlider.min, + max: configSlider.max + }, + start: configSlider.max, + step: configSlider.step, + measure: configSlider.measure, + }); + + updateSliderEffect(currentEffect); +}; + +const initEffect = () => { + noUiSlider.create(sliderElement, { + connect: 'lower', + range: { + min: 0, + max: 100, + }, + start: 100, + step: 0.1, + }); + + updateSliderEffect('none'); +}; + +effectList.addEventListener('change', (evt) => { + if(evt.target.matches('.effects__radio')) { + currentEffect = evt.target.value; + } + + changeSliderOptions(); +}); + +const resetEffect = () => { + noUiSlider.destroy(sliderElement); +}; + +export { initEffect, resetEffect }; diff --git a/js/form/slider-options.js b/js/form/slider-options.js new file mode 100644 index 0000000..646fb44 --- /dev/null +++ b/js/form/slider-options.js @@ -0,0 +1,48 @@ +const SLIDER_EFFECT_OPTIONS = { + none: { + filter: 'none', + min: 0, + max: 100, + step: 1, + start: 100, + measure: '', + }, + chrome: { + filter: 'grayscale', + min: 0, + max: 1, + step: 0.1, + start: 100, + measure: '', + }, + sepia: { + filter: 'sepia', + min: 0, + max: 1, + step: 0.1, + measure: '', + }, + marvin: { + filter: 'invert', + min: 0, + max: 100, + step: 1, + measure: '%', + }, + phobos: { + filter: 'blur', + min: 0, + max: 3, + step: 0.1, + measure: 'px', + }, + heat: { + filter: 'brightness', + min: 0, + max: 3, + step: 0.1, + measure: '', + }, +}; + +export { SLIDER_EFFECT_OPTIONS }; diff --git a/js/form/validation.js b/js/form/validation.js new file mode 100644 index 0000000..d398286 --- /dev/null +++ b/js/form/validation.js @@ -0,0 +1,70 @@ +const uploadForm = document.querySelector('.img-upload__form'); +const hashtagsInput = uploadForm.querySelector('.text__hashtags'); +const descriptionInput = uploadForm.querySelector('.text__description'); + +const MAX_QUATITY = 5; +const MAX_QUANTITY_SIMBOL = 140; + +let errorMessage = ''; + +const pristine = new Pristine(uploadForm, { + classTo: 'img-upload__form', + errorTextParent: 'img-upload__field-wrapper', + errorTextClass: 'img-upload__field-wrapper--error', +}); + +const checkRules = [ + { + check: (inputArray) => inputArray.some((element) => !/^#[a-zа-яё1-9]{1,19}$/i.test(element)), + error: 'Не допустимые символы!' + }, + { + check: (inputArray) => inputArray.length > MAX_QUATITY, + error: `Не более ${MAX_QUATITY} хэштегов!` + }, + { + check: (inputArray) => inputArray.some((element, num, Array) => Array.includes(element, num + 1)), + error: 'Хэштэги не должны повторяться!' + }, +]; + +const validHashtags = (value) => { + const inputText = value.toLowerCase().trim(); + const inputArray = inputText.split(' '); + + if(inputText.length === 0){ + return true; + } + + const checks = checkRules.every((ruleValidate) => { + const isInvalid = ruleValidate.check(inputArray); + + if(isInvalid) { + errorMessage = ruleValidate.error; + } + + return !isInvalid; + }); + + return checks; +}; + +const validDescription = (value) => { + const inputCommentArray = value; + inputCommentArray.split(' '); + + const isInvalid = inputCommentArray.length > MAX_QUANTITY_SIMBOL; + + if (isInvalid){ + errorMessage = `Не более ${MAX_QUANTITY_SIMBOL} символов!`; + } + + return !isInvalid; +}; + +const initValidation = () => { + pristine.addValidator(hashtagsInput, validHashtags, () => errorMessage); + pristine.addValidator(descriptionInput, validDescription, () => errorMessage); +}; + +export { initValidation }; diff --git a/js/main.js b/js/main.js index eee8ed0..1873c96 100644 --- a/js/main.js +++ b/js/main.js @@ -1,9 +1,11 @@ import { generatePhotos } from './generator'; import { renderThumbnails } from './render-thumbnails'; import { setPicturesListener } from './big-picture'; +import { initUploadModal } from './form/image-form'; const photos = generatePhotos(); renderThumbnails(photos); setPicturesListener(photos); +initUploadModal(); diff --git a/js/util.js b/js/util.js index 920a85e..1ca7757 100644 --- a/js/util.js +++ b/js/util.js @@ -27,5 +27,4 @@ const getRandomArrayElement = (elements) => elements[getRandomInteger(0, element const isEscapeKey = (evt) => evt.key === 'Escape'; const isEnterKey = (evt) => evt.key === 'Enter'; - export { getRandomInteger, createPreviousRangeGenerator, getRandomArrayElement, isEscapeKey, isEnterKey };