Skip to content

Commit 226f95e

Browse files
authored
Merge pull request #13 from Ocupuc123/module12-task1
2 parents 4958ed3 + 5602ac7 commit 226f95e

8 files changed

Lines changed: 142 additions & 74 deletions

File tree

js/filter.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { debounce } from './util.js';
2+
3+
const RENDER_DEBOUNCE = 500;
4+
const RANDOM_PHOTOS_COUNT = 10;
5+
const filters = document.querySelector('.img-filters');
6+
const filtersForm = filters.querySelector('.img-filters__form');
7+
const filterButtons = filters.querySelectorAll('.img-filters__button');
8+
9+
const FilterType = {
10+
RANDOM: 'filter-random',
11+
DISCUSSED: 'filter-discussed'
12+
};
13+
14+
const filterRandom = (photos) => {
15+
for (let i = photos.length - 1; i > 0; i--) {
16+
const j = Math.floor(Math.random() * (i + 1));
17+
[photos[i], photos[j]] = [photos[j], photos[i]];
18+
}
19+
20+
return photos.slice(0, RANDOM_PHOTOS_COUNT);
21+
};
22+
23+
const filterDiscussed = (photos) => photos.sort((a, b) => b.comments.length - a.comments.length);
24+
25+
const sortPhotos = (photos, filterType) => {
26+
const photosCopy = photos.slice();
27+
28+
switch (filterType) {
29+
case FilterType.RANDOM:
30+
return filterRandom(photosCopy);
31+
case FilterType.DISCUSSED:
32+
return filterDiscussed(photosCopy);
33+
default:
34+
return photosCopy;
35+
}
36+
};
37+
38+
const setFilter = (cb, photos) => {
39+
filters.classList.remove('img-filters--inactive');
40+
41+
const updateFilter = (filterType) => {
42+
const sortedPhotos = sortPhotos(photos, filterType);
43+
cb(sortedPhotos);
44+
};
45+
46+
const debouncedUpdateFilter = debounce(updateFilter, RENDER_DEBOUNCE);
47+
48+
filtersForm.addEventListener('click', (evt) => {
49+
const currentButton = evt.target.closest('.img-filters__button');
50+
51+
if (!currentButton || currentButton.classList.contains('img-filters__button--active')) {
52+
return;
53+
}
54+
55+
filterButtons.forEach((button) => {
56+
button.classList.remove('img-filters__button--active');
57+
});
58+
59+
currentButton.classList.add('img-filters__button--active');
60+
const currentFilterType = currentButton.id;
61+
62+
debouncedUpdateFilter(currentFilterType);
63+
});
64+
};
65+
66+
export { setFilter };

js/form.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,21 @@ const validateHashtags = (value) => {
7777

7878
const getHashtagsErrorMessage = () => lastErrorMessage;
7979

80-
const onFieldKeydown = (evt) => {
80+
const onHashtagFieldKeydown = (evt) => {
81+
if (isEscapeKey(evt)) {
82+
evt.stopPropagation();
83+
}
84+
};
85+
86+
const onCommentFieldKeydown = (evt) => {
8187
if (isEscapeKey(evt)) {
8288
evt.stopPropagation();
8389
}
8490
};
8591

8692
const setUploadFormSubmit = (onSubmit) => {
87-
formHashtagsField.addEventListener('keydown', onFieldKeydown);
88-
formCommentsField.addEventListener('keydown', onFieldKeydown);
93+
formHashtagsField.addEventListener('keydown', onHashtagFieldKeydown);
94+
formCommentsField.addEventListener('keydown', onCommentFieldKeydown);
8995

9096
pristine.addValidator(formHashtagsField, validateHashtags, getHashtagsErrorMessage);
9197
pristine.addValidator(formCommentsField, validateComments, ErrorMessage.MAX_LENGTH_FOR_COMMENTS);

js/functions.js

Lines changed: 0 additions & 26 deletions
This file was deleted.

js/main.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,22 @@
11
import { renderPictures } from './render-pictures.js';
2-
import { initPreview } from './preview.js';
3-
import { initUpload, onFormSubmit } from './upload-image.js';
2+
import { setPreview } from './preview.js';
3+
import { setUpload, onFormSubmit } from './upload-image.js';
44
import { showDataErrorAlert } from './util.js';
55
import { setUploadFormSubmit } from './form.js';
6+
import { setFilter } from './filter.js';
67
import { loadData } from './api.js';
78

89
const getData = async () => {
910
try {
1011
const photos = await loadData();
1112
renderPictures(photos);
12-
initPreview(photos);
13+
setPreview(photos);
14+
setFilter(renderPictures, photos);
1315
} catch (err) {
1416
showDataErrorAlert(err.message);
1517
}
1618
};
1719

1820
getData();
19-
initUpload();
21+
setUpload();
2022
setUploadFormSubmit(onFormSubmit);

js/preview.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const previewLikes = preview.querySelector('.likes-count');
1313
const previewComments = preview.querySelector('.social__comments');
1414
const previewCommentsLoader = preview.querySelector('.social__comments-loader');
1515
const previewCommentShownCount = preview.querySelector('.social__comment-shown-count');
16+
const previewCommentAddField = preview.querySelector('.social__footer-text');
1617
const previewCommentTotalCount = preview.querySelector('.social__comment-total-count');
1718
const previewCloseButton = preview.querySelector('.big-picture__cancel');
1819

@@ -44,16 +45,22 @@ const renderCommentsStep = () => {
4445
}
4546
};
4647

48+
const onCommentAddFieldKeydown = (evt) => {
49+
if (isEscapeKey(evt)) {
50+
evt.stopPropagation();
51+
}
52+
};
53+
4754
const onCommentsLoaderClick = (evt) => {
4855
evt.preventDefault();
4956
renderCommentsStep();
5057
};
5158

52-
const onPreviewCloseClick = () => {
59+
const onPreviewCloseButtonClick = () => {
5360
closePreview();
5461
};
5562

56-
const onPreviewKeydown = (evt) => {
63+
const onDocumentKeydown = (evt) => {
5764
if (isEscapeKey(evt)) {
5865
evt.preventDefault();
5966
closePreview();
@@ -85,10 +92,10 @@ const openPreview = (currentId, allPhotos) => {
8592

8693
previewCommentsLoader.classList.toggle('hidden', comments.length <= COMMENTS_COUNT_STEP);
8794

88-
document.addEventListener('keydown', onPreviewKeydown);
95+
document.addEventListener('keydown', onDocumentKeydown);
8996
};
9097

91-
const initPreview = (allPhotos) => {
98+
const setPreview = (allPhotos) => {
9299

93100
pictures.addEventListener('click', (evt) => {
94101
const targetPicture = evt.target.closest('.picture');
@@ -101,15 +108,17 @@ const initPreview = (allPhotos) => {
101108
});
102109

103110
previewCommentsLoader.addEventListener('click', onCommentsLoaderClick);
104-
previewCloseButton.addEventListener('click', onPreviewCloseClick);
111+
previewCloseButton.addEventListener('click', onPreviewCloseButtonClick);
112+
previewCommentAddField.addEventListener('keydown', onCommentAddFieldKeydown);
105113
};
106114

107115
function closePreview() {
108116
body.classList.remove('modal-open');
109117
previewCommentsLoader.classList.remove('hidden');
110118
preview.classList.add('hidden');
119+
previewCommentAddField.value = '';
111120

112-
document.removeEventListener('keydown', onPreviewKeydown);
121+
document.removeEventListener('keydown', onDocumentKeydown);
113122
}
114123

115-
export { initPreview };
124+
export { setPreview };

js/render-pictures.js

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,27 @@
11
const pictures = document.querySelector('.pictures');
22
const pictureFragment = document.querySelector('#picture').content;
33
const pictureTemplate = pictureFragment.querySelector('.picture');
4-
const fragment = document.createDocumentFragment();
54

65
const renderPictures = (photos) => {
6+
const pictureListFragment = document.createDocumentFragment();
7+
const existingPictures = pictures.querySelectorAll('.picture');
8+
existingPictures.forEach((picture) => picture.remove());
9+
710
photos.forEach(({ id, url, description, comments, likes }) => {
8-
const pictureTemplateClone = pictureTemplate.cloneNode(true);
9-
const pictureImage = pictureTemplateClone.querySelector('.picture__img');
11+
const picture = pictureTemplate.cloneNode(true);
12+
const pictureImage = picture.querySelector('.picture__img');
1013

1114
pictureImage.src = url;
1215
pictureImage.alt = description;
1316

14-
pictureTemplateClone.querySelector('.picture__comments').textContent = comments.length;
15-
pictureTemplateClone.querySelector('.picture__likes').textContent = likes;
16-
pictureTemplateClone.dataset.pictureId = id;
17+
picture.querySelector('.picture__comments').textContent = comments.length;
18+
picture.querySelector('.picture__likes').textContent = likes;
19+
picture.dataset.pictureId = id;
1720

18-
fragment.appendChild(pictureTemplateClone);
21+
pictureListFragment.appendChild(picture);
1922
});
2023

21-
pictures.appendChild(fragment);
24+
pictures.appendChild(pictureListFragment);
2225
};
2326

2427
export { renderPictures };

js/upload-image.js

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ const effectConfig = {
5454

5555
const body = document.body;
5656
const upload = document.querySelector('.img-upload');
57+
const uploadSubmitButton = upload.querySelector('#upload-submit');
5758
const uploadFile = upload.querySelector('#upload-file');
5859
const uploadForm = upload.querySelector('#upload-select-image');
5960
const uploadOverlay = upload.querySelector('.img-upload__overlay');
@@ -76,48 +77,51 @@ const showAlert = (type) => {
7677
const alert = fragment.querySelector(`.${type}`).cloneNode(true);
7778
const alertCloseButton = alert.querySelector(`.${type}__button`);
7879

79-
const onAlertKeydown = (evt) => {
80+
const onDocumentKeydown = (evt) => {
8081
if (isEscapeKey(evt)) {
8182
evt.preventDefault();
8283
closeAlert();
8384
}
8485
};
8586

86-
const onAlertOutsideClick = (evt) => {
87+
const onDocumentClick = (evt) => {
8788
if (!evt.target.closest(`.${type}__inner`)) {
8889
closeAlert();
8990
}
9091
};
9192

92-
const onAlertCloseClick = () => {
93+
const onAlertCloseButtonClick = () => {
9394
closeAlert();
9495
};
9596

9697
function closeAlert() {
9798
alert.remove();
98-
document.removeEventListener('keydown', onAlertKeydown);
99-
document.removeEventListener('click', onAlertOutsideClick);
99+
document.removeEventListener('keydown', onDocumentKeydown);
100+
document.removeEventListener('click', onDocumentClick);
100101
}
101102

102-
alertCloseButton.addEventListener('click', onAlertCloseClick);
103-
document.addEventListener('keydown', onAlertKeydown);
104-
document.addEventListener('click', onAlertOutsideClick);
103+
alertCloseButton.addEventListener('click', onAlertCloseButtonClick);
104+
document.addEventListener('keydown', onDocumentKeydown);
105+
document.addEventListener('click', onDocumentClick);
105106
body.appendChild(alert);
106107
};
107108

108-
109109
const applyFilterEffect = (effect, value) => `${effectConfig[effect]?.property}(${parseFloat(value)}${effectConfig[effect]?.unit})`;
110110

111111
const applyTransformScale = (value) => `scale(${parseFloat(value) / 100})`;
112112

113+
const toggleSubmitButton = (isDisabled) => {
114+
uploadSubmitButton.disabled = isDisabled;
115+
};
116+
113117
const onScaleControlClick = (direction) => {
114118
currentScale = Math.min(Math.max(currentScale + (direction * ScaleStep.STEP), ScaleStep.MIN), ScaleStep.MAX);
115119

116120
uploadScaleControlInput.value = `${currentScale}%`;
117121
uploadPreview.style.transform = applyTransformScale(currentScale);
118122
};
119123

120-
const onUploadKeydown = (evt) => {
124+
const onDocumentKeydownUpload = (evt) => {
121125
if (document.querySelector('.success') || document.querySelector('.error')) {
122126
return;
123127
}
@@ -128,11 +132,13 @@ const onUploadKeydown = (evt) => {
128132
}
129133
};
130134

131-
const onUploadCloseClick = () => {
135+
const onUploadCloseButtonClick = () => {
132136
closeUpload();
133137
};
134138

135139
const onFormSubmit = async (data) => {
140+
toggleSubmitButton(true);
141+
136142
try {
137143
const request = await sendData(data);
138144

@@ -143,6 +149,8 @@ const onFormSubmit = async (data) => {
143149
} catch {
144150
showAlert('error');
145151
}
152+
153+
toggleSubmitButton(false);
146154
};
147155

148156
const onSliderUpdate = () => {
@@ -188,7 +196,6 @@ const checkEffectSliderVisibility = (effect) => {
188196
};
189197

190198
const clearForm = () => {
191-
uploadFile.value = '';
192199
uploadPreview.style = '';
193200
uploadForm.reset();
194201
currentEffect = 'none';
@@ -205,10 +212,10 @@ const openUpload = () => {
205212
uploadOverlay.classList.remove('hidden');
206213
checkEffectSliderVisibility('none');
207214

208-
document.addEventListener('keydown', onUploadKeydown);
215+
document.addEventListener('keydown', onDocumentKeydownUpload);
209216
};
210217

211-
const initUpload = () => {
218+
const setUpload = () => {
212219
uploadFile.addEventListener('change', openUpload);
213220

214221
uploadScaleControlSmaller.addEventListener('click', () => {
@@ -219,7 +226,7 @@ const initUpload = () => {
219226
onScaleControlClick(ScaleDirection.INCREASE);
220227
});
221228

222-
uploadCloseButton.addEventListener('click', onUploadCloseClick);
229+
uploadCloseButton.addEventListener('click', onUploadCloseButtonClick);
223230
uploadEffects.addEventListener('change', () => {
224231
checkEffectSliderVisibility(uploadForm['effect'].value);
225232
});
@@ -231,7 +238,7 @@ function closeUpload() {
231238
body.classList.remove('modal-open');
232239
uploadOverlay.classList.add('hidden');
233240

234-
document.removeEventListener('keydown', onUploadKeydown);
241+
document.removeEventListener('keydown', onDocumentKeydownUpload);
235242
}
236243

237-
export { initUpload, onFormSubmit };
244+
export { setUpload, onFormSubmit };

0 commit comments

Comments
 (0)