Skip to content

Commit 9e62c26

Browse files
authored
Merge pull request #11 from ksenya3112/module9-task1
2 parents 84300e5 + d4a1d17 commit 9e62c26

5 files changed

Lines changed: 80 additions & 6 deletions

File tree

index.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ <h2 class="pictures__title visually-hidden">Фотографии других
3232
<section class="img-upload">
3333
<div class="img-upload__wrapper">
3434
<h2 class="img-upload__title visually-hidden">Загрузка фотографии</h2>
35-
<form class="img-upload__form" id="upload-select-image" autocomplete="off">
35+
<form class="img-upload__form" method="POST" enctype="multipart/form-data"
36+
action="https://31.javascript.htmlacademy.pro/kekstagram" autocomplete="off">
3637

3738
<!-- Изначальное состояние поля для загрузки изображения -->
3839
<fieldset class="img-upload__start">
@@ -249,6 +250,7 @@ <h2 class="success__title">Изображение успешно загруже
249250
<h2 class="data-error__title">Не удалось загрузить данные</h2>
250251
</section>
251252
</template>
253+
<script src="./vendor/pristine/pristine.min.js"></script>
252254
<script src="./js/main.js" type="module"></script>
253255
</body>
254256

js/form.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { isEsc } from './util.js';
2+
3+
const uploadForm = document.querySelector('.img-upload__form');
4+
const fileInput = uploadForm.querySelector('.img-upload__input');
5+
const overlay = uploadForm.querySelector('.img-upload__overlay');
6+
const closeButton = uploadForm.querySelector('.img-upload__cancel');
7+
const hashtagInput = uploadForm.querySelector('.text__hashtags');
8+
const commentInput = uploadForm.querySelector('.text__description');
9+
10+
// Инициализация Pristine
11+
const pristine = new Pristine(uploadForm, {
12+
classTo: 'img-upload__field-wrapper',
13+
errorTextParent: 'img-upload__field-wrapper',
14+
errorTextClass: 'img-upload__field-wrapper--error',
15+
});
16+
17+
// Закрытие формы
18+
const closeUploadModal = () => {
19+
overlay.classList.add('hidden');
20+
document.body.classList.remove('modal-open');
21+
uploadForm.reset(); // Сбрасывает все поля
22+
pristine.reset(); // Очищает ошибки валидации
23+
document.removeEventListener('keydown', onDocumentKeydown);
24+
};
25+
26+
// Обработчик Esc (не закрывать, если фокус в полях ввода)
27+
function onDocumentKeydown(evt) {
28+
if (isEsc(evt) && document.activeElement !== hashtagInput && document.activeElement !== commentInput) {
29+
evt.preventDefault();
30+
closeUploadModal();
31+
}
32+
}
33+
34+
// Открытие формы при выборе файла
35+
fileInput.addEventListener('change', () => {
36+
overlay.classList.remove('hidden');
37+
document.body.classList.add('modal-open');
38+
document.addEventListener('keydown', onDocumentKeydown);
39+
});
40+
41+
closeButton.addEventListener('click', closeUploadModal);
42+
43+
// Валидация хэштегов
44+
const MAX_HASHTAGS = 5;
45+
const VALID_SYMBOLS = /^#[a-zа-яё0-9]{1,19}$/i;
46+
47+
const validateHashtags = (value) => {
48+
const hashtags = value.trim().toLowerCase().split(/\s+/).filter(Boolean);
49+
50+
const hasValidCount = hashtags.length <= MAX_HASHTAGS;
51+
const hasUniqueHashtags = new Set(hashtags).size === hashtags.length;
52+
const hasValidSymbols = hashtags.every((tag) => VALID_SYMBOLS.test(tag));
53+
54+
return hasValidCount && hasUniqueHashtags && hasValidSymbols;
55+
};
56+
57+
pristine.addValidator(hashtagInput, validateHashtags, 'Некорректные хэштеги (макс 5, без повторов, начинаются с #)');
58+
59+
// Валидация комментария
60+
pristine.addValidator(commentInput, (val) => val.length <= 140, 'Максимум 140 символов');
61+
62+
// Отправка формы
63+
uploadForm.addEventListener('submit', (evt) => {
64+
const isValid = pristine.validate();
65+
if (!isValid) {
66+
evt.preventDefault();
67+
}
68+
});

js/full-size-picture.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { isEsc } from './util.js';
2+
13
const COMMENTS_STEP = 5;
24

35
const fullSizePictureElement = document.querySelector('.big-picture');
@@ -61,13 +63,12 @@ const onCloseButtonClick = () => {
6163
//Удаление обработчика с кнопки при закрытии, чтобы не накапливались
6264
commentsLoader.removeEventListener('click', onCommentsLoaderClick);
6365
};
64-
65-
function onDocumentKeydown(evt) {
66-
if (evt.key === 'Escape') {
66+
const onDocumentKeydown = (evt) => {
67+
if (isEsc(evt)) {
6768
evt.preventDefault();
6869
onCloseButtonClick();
6970
}
70-
}
71+
};
7172

7273
//Открытие и заполнение данными
7374
const openFullSizePicture = (data) => {

js/main.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { generatePhotos } from './data.js';
22

33
import './util.js';
44
import './data.js';
5+
import './form.js';
56

67
import { renderThumbnails } from './thumbnails.js';
78
renderThumbnails(generatePhotos());

js/util.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
const getRandomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
22

3-
export { getRandomInt };
3+
const isEsc = (evt) => evt.key === 'Escape';
4+
5+
export { getRandomInt, isEsc };

0 commit comments

Comments
 (0)