Skip to content

Commit 1addf9e

Browse files
authored
Merge pull request #9 from zarram89/module9-task1
2 parents 25eacef + a0353b6 commit 1addf9e

9 files changed

Lines changed: 173 additions & 11 deletions

File tree

index.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<meta name="viewport" content="width=device-width,initial-scale=1">
77
<link rel="stylesheet" href="css/normalize.css">
88
<link rel="stylesheet" href="css/style.css">
9+
<link rel="stylesheet" href="vendor/nouislider/nouislider.css">
910
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
1011
<title>Кекстаграм</title>
1112
</head>
@@ -31,7 +32,7 @@ <h2 class="pictures__title visually-hidden">Фотографии других
3132
<section class="img-upload">
3233
<div class="img-upload__wrapper">
3334
<h2 class="img-upload__title visually-hidden">Загрузка фотографии</h2>
34-
<form class="img-upload__form" id="upload-select-image" autocomplete="off">
35+
<form class="img-upload__form" id="upload-select-image" method="post" action="https://31.javascript.htmlacademy.pro/kekstagram" enctype="multipart/form-data" autocomplete="off">
3536

3637
<!-- Изначальное состояние поля для загрузки изображения -->
3738
<fieldset class="img-upload__start">
@@ -120,7 +121,7 @@ <h2 class="img-upload__title visually-hidden">Загрузка фотограф
120121
<input class="text__hashtags" name="hashtags" placeholder="#ХэшТег">
121122
</div>
122123
<div class="img-upload__field-wrapper">
123-
<textarea class="text__description" name="description" placeholder="Ваш комментарий..."></textarea>
124+
<textarea class="text__description" name="description" placeholder="Ваш комментарий..." maxlength="140"></textarea>
124125
</div>
125126
</fieldset>
126127

@@ -234,6 +235,8 @@ <h2 class="success__title">Изображение успешно загруже
234235
<h2 class="data-error__title">Не удалось загрузить данные</h2>
235236
</section>
236237
</template>
238+
<script src="vendor/pristine/pristine.min.js"></script>
239+
<script src="vendor/nouislider/nouislider.js"></script>
237240
<script src="js/main.js" type="module"></script>
238241
</body>
239242

js/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ import { getPictures } from './mock/pictures.js';
22
import { renderGallery } from './ui/gallery.js';
33
import { initBigPicture } from './ui/big-picture/meta.js';
44
import { initCommentsLoader } from './ui/big-picture/comments.js';
5+
import { initForm } from './ui/form/index.js';
56

67
const container = document.querySelector('.pictures');
78
const template = document.querySelector('#picture')?.content?.querySelector('.picture');
89

910
initBigPicture();
1011
initCommentsLoader();
12+
initForm();
1113

1214
if (container && template) {
1315
renderGallery(getPictures(), container, template);

js/ui/big-picture/meta.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const renderMeta = ({ url, likes, description }) => {
2020
caption.textContent = description;
2121
};
2222

23-
const open = (data) => {
23+
const showBigPicture = (data) => {
2424
if (!data || isOpen) {
2525
return;
2626
}
@@ -37,7 +37,7 @@ const open = (data) => {
3737
renderComments();
3838
};
3939

40-
const close = () => {
40+
const hideBigPicture = () => {
4141
if (!isOpen) {
4242
return;
4343
}
@@ -53,12 +53,12 @@ const close = () => {
5353
function onDocumentKeydown(evt) {
5454
if (isEscapeKey(evt)) {
5555
evt.preventDefault();
56-
close();
56+
hideBigPicture();
5757
}
5858
}
5959

6060
function onCancelButtonClick() {
61-
close();
61+
hideBigPicture();
6262
}
6363

6464
const initBigPicture = () => {
@@ -70,8 +70,4 @@ const initBigPicture = () => {
7070
cancelButton.addEventListener('click', onCancelButtonClick);
7171
};
7272

73-
export {
74-
initBigPicture,
75-
open as showBigPicture,
76-
close as hideBigPicture,
77-
};
73+
export { initBigPicture, showBigPicture, hideBigPicture };

js/ui/form/const.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const MAX_HASHTAG_COUNT = 5;
2+
const MAX_COMMENT_LENGTH = 140;
3+
const VALID_SYMBOLS = /^#[a-zа-яё0-9]{1,19}$/i;
4+
5+
export { MAX_HASHTAG_COUNT, MAX_COMMENT_LENGTH, VALID_SYMBOLS };

js/ui/form/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { initModal } from './modal.js';
2+
import { initValidation, resetValidation } from './validation.js';
3+
import { initSubmit } from './submit.js';
4+
5+
const initForm = () => {
6+
initValidation();
7+
initSubmit();
8+
9+
initModal(() => {
10+
resetValidation();
11+
});
12+
};
13+
14+
export { initForm };

js/ui/form/modal.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { isEscapeKey } from '../../utils/common.js';
2+
3+
const body = document.body;
4+
const form = document.querySelector('.img-upload__form');
5+
const overlay = form.querySelector('.img-upload__overlay');
6+
const cancelButton = form.querySelector('.img-upload__cancel');
7+
const fileField = form.querySelector('.img-upload__input');
8+
9+
let onCloseCallback = null;
10+
11+
const showModal = () => {
12+
overlay.classList.remove('hidden');
13+
body.classList.add('modal-open');
14+
document.addEventListener('keydown', onDocumentKeydown);
15+
};
16+
17+
const hideModal = () => {
18+
form.reset();
19+
fileField.value = '';
20+
21+
overlay.classList.add('hidden');
22+
body.classList.remove('modal-open');
23+
document.removeEventListener('keydown', onDocumentKeydown);
24+
25+
if (onCloseCallback) {
26+
onCloseCallback();
27+
}
28+
};
29+
30+
const initModal = (cb) => {
31+
onCloseCallback = cb;
32+
33+
fileField.addEventListener('change', showModal);
34+
cancelButton.addEventListener('click', hideModal);
35+
};
36+
37+
function onDocumentKeydown(evt) {
38+
if (isEscapeKey(evt)) {
39+
evt.preventDefault();
40+
hideModal();
41+
}
42+
}
43+
44+
export { initModal, hideModal };

js/ui/form/submit.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { isValid } from './validation.js';
2+
3+
const form = document.querySelector('.img-upload__form');
4+
5+
const initSubmit = () => {
6+
form.addEventListener('submit', (evt) => {
7+
const valid = isValid();
8+
9+
if (!valid) {
10+
evt.preventDefault();
11+
}
12+
});
13+
};
14+
15+
export { initSubmit };

js/ui/form/utils.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { VALID_SYMBOLS } from './const.js';
2+
3+
const getTags = (value) =>
4+
value
5+
.trim()
6+
.split(/\s+/)
7+
.filter((tag) => tag.trim().length);
8+
9+
const isValidTag = (tag) => VALID_SYMBOLS.test(tag);
10+
11+
const isValidCount = (tags, max) => tags.length <= max;
12+
13+
const hasUniqueTags = (tags) => {
14+
const lowerCaseTags = tags.map((tag) => tag.toLowerCase());
15+
return lowerCaseTags.length === new Set(lowerCaseTags).size;
16+
};
17+
18+
export { getTags, isValidTag, isValidCount, hasUniqueTags };

js/ui/form/validation.js

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { MAX_HASHTAG_COUNT, MAX_COMMENT_LENGTH } from './const.js';
2+
import { getTags, isValidTag, isValidCount, hasUniqueTags } from './utils.js';
3+
4+
const form = document.querySelector('.img-upload__form');
5+
const hashtagField = form.querySelector('.text__hashtags');
6+
const commentField = form.querySelector('.text__description');
7+
8+
const ERROR_MESSAGES = {
9+
hashtags: {
10+
count: () => 'превышено количество хэштегов',
11+
unique: () => 'хэштеги повторяются',
12+
format: () => 'введён невалидный хэштег',
13+
},
14+
comment: {
15+
length: (max) => `длина комментария больше ${max} символов`,
16+
},
17+
};
18+
19+
const formConfig = {
20+
classTo: 'img-upload__field-wrapper',
21+
errorTextParent: 'img-upload__field-wrapper',
22+
errorTextClass: 'img-upload__field-wrapper--error',
23+
};
24+
25+
const pristine = new Pristine(form, formConfig);
26+
27+
const initValidation = () => {
28+
[hashtagField, commentField].forEach((field) => {
29+
field.addEventListener('keydown', (evt) => {
30+
if (evt.key === 'Escape') {
31+
evt.stopPropagation();
32+
}
33+
});
34+
});
35+
36+
pristine.addValidator(
37+
hashtagField,
38+
(value) => isValidCount(getTags(value), MAX_HASHTAG_COUNT),
39+
ERROR_MESSAGES.hashtags.count()
40+
);
41+
42+
pristine.addValidator(
43+
hashtagField,
44+
(value) => hasUniqueTags(getTags(value)),
45+
ERROR_MESSAGES.hashtags.unique()
46+
);
47+
48+
pristine.addValidator(
49+
hashtagField,
50+
(value) => getTags(value).every(isValidTag),
51+
ERROR_MESSAGES.hashtags.format()
52+
);
53+
54+
pristine.addValidator(
55+
commentField,
56+
(value) => value.length <= MAX_COMMENT_LENGTH,
57+
ERROR_MESSAGES.comment.length(MAX_COMMENT_LENGTH)
58+
);
59+
};
60+
61+
const isValid = () => pristine.validate();
62+
63+
const resetValidation = () => pristine.reset();
64+
65+
export { initValidation, isValid, resetValidation };

0 commit comments

Comments
 (0)