Skip to content

Commit eca24e6

Browse files
authored
Merge pull request #13 from AnastasiiaXX/module12-task2
2 parents 3bc59d0 + 39b4c39 commit eca24e6

12 files changed

Lines changed: 102 additions & 77 deletions

index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ <h2 class="img-upload__title visually-hidden">Загрузка фотограф
3636

3737
<!-- Изначальное состояние поля для загрузки изображения -->
3838
<fieldset class="img-upload__start">
39-
<input type="file" id="upload-file" class="img-upload__input visually-hidden" name="filename" required>
39+
<input type="file" id="upload-file" class="img-upload__input visually-hidden" name="filename"
40+
accept="image/png, image/jpeg" required>
4041
<label for="upload-file" class="img-upload__label img-upload__control">Загрузить</label>
4142
</fieldset>
4243

js/helpers.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const debounce = (callback, timeoutDelay = 500) => {
33

44
return (...rest) => {
55
clearTimeout(timeoutId);
6-
timeoutId = setTimeout(() => callback.apply(this, rest), timeoutDelay);
6+
timeoutId = setTimeout(() => callback(...rest), timeoutDelay);
77
};
88
};
99
const isEscapeKey = (evt) => evt.key === 'Escape';

js/image-filters.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
1-
const EFFECTS = {
1+
const effects = {
22
chrome: { filter: 'grayscale', min: 0, max: 1, step: 0.1, unit: ''},
33
sepia: { filter: 'sepia', min: 0, max: 1, step: 0.1, unit: ''},
44
marvin: { filter: 'invert', min: 0, max: 100, step: 1, unit: '%'},
55
phobos: { filter: 'blur', min: 0, max: 3, step: 0.1, unit: 'px'},
66
heat: { filter: 'brightness', min: 1, max: 3, step: 0.1, unit: ''}
77
};
88

9-
const form = document.querySelector('.img-upload__form');
9+
const DEFAULT_EFFECT = 'none';
1010

11+
const form = document.querySelector('.img-upload__form');
1112
const slider = form.querySelector('.effect-level__slider');
1213
const sliderContainer = form.querySelector('.img-upload__effect-level');
1314
const uploadedImage = form.querySelector('.img-upload__preview img');
1415
const effectRadios = form.querySelectorAll('input[name="effect"]');
1516
const inputValue = form.querySelector('.effect-level__value');
17+
const noneRadioBtn = form.querySelector('input[value="none"]');
1618

1719
const initImageEffects = () => {
1820
let selectedFilter = 'none';
@@ -32,8 +34,8 @@ const initImageEffects = () => {
3234
if (selectedFilter === 'none') {
3335
return;
3436
}
35-
const value = slider.noUiSlider.get();
36-
const effect = EFFECTS[selectedFilter];
37+
const value = parseFloat(slider.noUiSlider.get());
38+
const effect = effects[selectedFilter];
3739
const filterStyle = `${effect.filter}(${value}${effect.unit})`;
3840
uploadedImage.style.filter = filterStyle;
3941
inputValue.value = value;
@@ -42,13 +44,13 @@ const initImageEffects = () => {
4244
effectRadios.forEach((radio) => {
4345
radio.addEventListener('change', () => {
4446
selectedFilter = radio.value;
45-
if (selectedFilter === 'none') {
47+
if (selectedFilter === DEFAULT_EFFECT) {
4648
sliderContainer.classList.add('hidden');
4749
uploadedImage.style.filter = '';
4850
} else {
4951
sliderContainer.classList.remove('hidden');
5052

51-
const effect = EFFECTS[selectedFilter];
53+
const effect = effects[selectedFilter];
5254
slider.noUiSlider.updateOptions({
5355
range: { min: effect.min, max: effect.max },
5456
start: effect.max,
@@ -60,7 +62,6 @@ const initImageEffects = () => {
6062
};
6163

6264
const resetImageEffects = () => {
63-
const noneRadioBtn = form.querySelector('input[value="none"]');
6465
noneRadioBtn.checked = true;
6566
sliderContainer.classList.add('hidden');
6667
uploadedImage.style.filter = '';

js/image-scale.js

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,35 @@
1+
const MIN_SCALE = 25;
2+
const MAX_SCALE = 100;
3+
const SCALE_STEP = 25;
4+
const PERCENT_DIVIDER = 100;
5+
16
const form = document.querySelector('.img-upload__form');
27
const scaleSmallerBtn = form.querySelector('.scale__control--smaller');
38
const scaleBiggerBtn = form.querySelector('.scale__control--bigger');
49
const scaleControlValue = form.querySelector('.scale__control--value');
510
const uploadedImage = form.querySelector('.img-upload__preview img');
611

7-
let currentScale = 100;
12+
let currentScale = MAX_SCALE;
813
const initImageScale = () => {
914
scaleSmallerBtn.addEventListener('click', () => {
10-
if (currentScale > 25) {
11-
currentScale -= 25;
15+
if (currentScale > MIN_SCALE) {
16+
currentScale -= SCALE_STEP;
1217
scaleControlValue.value = `${currentScale}%`;
13-
uploadedImage.style.transform = `scale(${currentScale / 100})`;
18+
uploadedImage.style.transform = `scale(${currentScale / PERCENT_DIVIDER})`;
1419
}
1520
});
1621

1722
scaleBiggerBtn.addEventListener('click', () => {
18-
if (currentScale < 100) {
19-
currentScale += 25;
23+
if (currentScale < MAX_SCALE) {
24+
currentScale += SCALE_STEP;
2025
scaleControlValue.value = `${currentScale}%`;
21-
uploadedImage.style.transform = `scale(${currentScale / 100})`;
26+
uploadedImage.style.transform = `scale(${currentScale / PERCENT_DIVIDER})`;
2227
}
2328
});
2429
};
2530

2631
const resetImageScale = () => {
27-
currentScale = 100;
32+
currentScale = MAX_SCALE;
2833
scaleControlValue.value = `${currentScale}%`;
2934
uploadedImage.style.transform = 'scale(1)';
3035
};

js/main.js

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
1-
import { renderThumbnails } from './thumbnails.js';
1+
import { renderThumbnails, clearThumbnails } from './thumbnails.js';
22
import { showFullPhoto } from './show-full-photo.js';
3-
import { initUploadForm, resetUploadForm } from './upload-form.js';
4-
import { getData } from './api';
3+
import { initUploadForm, resetUploadForm, setUploadFormSubmit} from './upload-form.js';
4+
import { getData } from './api.js';
55
import { showDataError, showSuccessMessage, showErrorMessage } from './notifications.js';
6-
import { setUploadFormSubmit } from './upload-form.js';
76
import { showFilters, initPhotosFiltering } from './photos-filters.js';
7+
import { debounce } from './helpers.js';
8+
9+
const RERENDER_TIME = 500;
10+
const rerenderThumbnails = (photos) => {
11+
clearThumbnails();
12+
renderThumbnails(photos);
13+
};
14+
const debouncedRender = debounce(rerenderThumbnails, RERENDER_TIME);
815

916
initUploadForm();
1017
getData()
1118
.then((photos) => {
1219
renderThumbnails(photos);
1320
showFilters();
14-
initPhotosFiltering(photos);
21+
initPhotosFiltering(photos, debouncedRender);
1522
showFullPhoto(photos);
1623
})
1724
.catch((e)=> {

js/modal.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
import { isEscapeKey } from './helpers.js';
22
let currentHandler = null;
33

4-
export const closeModal = (modalElement, bodyElement) => {
4+
export const closeModal = (modalElement, bodyElement, onClose = null) => {
55
modalElement.classList.add('hidden');
66
bodyElement.classList.remove('modal-open');
77
document.removeEventListener('keydown', currentHandler);
8+
9+
if (onClose) {
10+
onClose();
11+
}
812
};
9-
export const openModal = (modalElement, bodyElement) => {
13+
export const openModal = (modalElement, bodyElement, onClose = null) => {
1014
currentHandler = (evt) => {
1115
if (isEscapeKey(evt)) {
1216
evt.preventDefault();
13-
closeModal(modalElement, bodyElement);
17+
closeModal(modalElement, bodyElement, onClose);
1418
}
1519
};
1620
modalElement.classList.remove('hidden');

js/notifications.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@ const showMessage = (templateId, buttonClass) => {
2323

2424
const closeMessage = () => {
2525
messageDiv.remove();
26-
document.removeEventListener('keydown', handleEscape);
26+
document.removeEventListener('keydown', handleEscape, true);
2727
messageDiv.removeEventListener('click', handleOutsideClick);
2828
};
2929

3030
handleEscape = (evt) => {
31+
evt.stopPropagation();
3132
if (isEscapeKey(evt)) {
3233
closeMessage();
3334
}
@@ -39,7 +40,7 @@ const showMessage = (templateId, buttonClass) => {
3940
}
4041
};
4142
messageButton.addEventListener('click', closeMessage);
42-
document.addEventListener('keydown', handleEscape);
43+
document.addEventListener('keydown', handleEscape, true);
4344
messageDiv.addEventListener('click', handleOutsideClick);
4445
};
4546

js/photos-filters.js

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,3 @@
1-
import { renderThumbnails } from './thumbnails.js';
2-
import { debounce } from './helpers.js';
3-
4-
const RERENDER_TIME = 500;
5-
61
const filtersBlock = document.querySelector('.img-filters');
72
const filterDefaultBtn = document.querySelector('#filter-default');
83
const filterRandomBtn = document.querySelector('#filter-random');
@@ -12,39 +7,31 @@ const showFilters = () => {
127
filtersBlock.classList.remove('img-filters--inactive');
138
};
149

15-
const clearThumbnails = () => {
16-
const thumbnails = document.querySelectorAll('.picture');
17-
thumbnails.forEach((thumbnail) => {
18-
thumbnail.remove();
19-
});
20-
};
21-
22-
const toggleActiveBtn = (btnClicked, activeclass) => {
23-
const activeBtn = document.querySelector(`.${activeclass}`);
24-
activeBtn.classList.remove(activeclass);
25-
btnClicked.classList.add(activeclass);
26-
};
27-
28-
const rerenderThumbnails = (btn, photos, cb = null) => {
29-
toggleActiveBtn(btn, 'img-filters__button--active');
30-
const photosToRender = cb ? cb(photos) : photos;
31-
clearThumbnails();
32-
renderThumbnails(photosToRender);
10+
const toggleActiveBtn = (btnClicked, activeClass) => {
11+
const activeBtn = document.querySelector(`.${activeClass}`);
12+
if (activeBtn) {
13+
activeBtn.classList.remove(activeClass);
14+
}
15+
btnClicked.classList.add(activeClass);
16+
void btnClicked.offsetWidth;
3317
};
18+
const initPhotosFiltering = (photos, onRender) => {
3419

35-
const debouncedRender = debounce(rerenderThumbnails, RERENDER_TIME);
36-
37-
const initPhotosFiltering = (photos) => {
3820
filterDefaultBtn.addEventListener('click', () => {
39-
debouncedRender(filterDefaultBtn, photos);
21+
toggleActiveBtn(filterDefaultBtn, 'img-filters__button--active');
22+
onRender(photos);
4023
});
4124

4225
filterRandomBtn.addEventListener('click', () => {
43-
debouncedRender(filterRandomBtn, photos, () => photos.slice().sort(() => 0.5 - Math.random()).slice(0, 10));
26+
toggleActiveBtn(filterRandomBtn, 'img-filters__button--active');
27+
const randomPhotos = photos.slice().sort(() => 0.5 - Math.random()).slice(0, 10);
28+
onRender(randomPhotos);
4429
});
4530

4631
filterDiscussedBtn.addEventListener('click', () => {
47-
debouncedRender(filterDiscussedBtn, photos, () => photos.slice().sort((a, b) => b.comments.length - a.comments.length));
32+
toggleActiveBtn(filterDiscussedBtn, 'img-filters__button--active');
33+
const discussedPhotos = photos.slice().sort((a, b) => b.comments.length - a.comments.length);
34+
onRender(discussedPhotos);
4835
});
4936
};
5037

js/show-full-photo.js

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const body = document.querySelector('body');
66
const closeModalButton = document.querySelector('.big-picture__cancel');
77
const comments = document.querySelector('.social__comments');
88
const pictureContainer = document.querySelector('.pictures');
9-
let currentLoadMoreHandler = null;
9+
1010
const fillPhotoData = (currentPhoto) => {
1111
const fullPhotoImage = document.querySelector('.big-picture__img img');
1212
const fullPhotoDescription = document.querySelector('.social__caption');
@@ -24,6 +24,7 @@ const fillPhotoData = (currentPhoto) => {
2424
export const showFullPhoto = (photos) => {
2525
const commentsLoaderBtn = document.querySelector('.comments-loader');
2626
const shownCommentsCount = document.querySelector('.social__comment-shown-count');
27+
2728
pictureContainer.addEventListener('click', (evt) => {
2829
const thumbnail = evt.target.closest('.picture');
2930
if (!thumbnail) {
@@ -38,20 +39,13 @@ export const showFullPhoto = (photos) => {
3839
commentsLoaderBtn.classList.toggle('hidden', currentPhoto.comments.length <= 5);
3940
const pagination = paginateComments(currentPhoto.comments, comments);
4041
shownCommentsCount.textContent = pagination.getShownCount();
41-
const handleLoadMore = () => {
42+
43+
commentsLoaderBtn.onclick = () => {
4244
pagination.loadMore();
4345
shownCommentsCount.textContent = pagination.getShownCount();
4446
commentsLoaderBtn.classList.toggle('hidden', pagination.getShownCount() >= currentPhoto.comments.length);
4547
};
46-
if (currentLoadMoreHandler) {
47-
commentsLoaderBtn.removeEventListener('click', currentLoadMoreHandler);
48-
currentLoadMoreHandler = null;
49-
}
50-
currentLoadMoreHandler = handleLoadMore;
51-
commentsLoaderBtn.addEventListener('click', handleLoadMore);
52-
5348
});
49+
5450
closeModalButton.addEventListener('click', () => closeModal(fullPhotoModal, body));
5551
};
56-
57-

js/thumbnails.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,9 @@ export const renderThumbnails = (photos) => {
2525

2626
photoContainer.append(fragment);
2727
};
28+
export const clearThumbnails = () => {
29+
const thumbnails = document.querySelectorAll('.picture');
30+
thumbnails.forEach((thumbnail) => {
31+
thumbnail.remove();
32+
});
33+
};

0 commit comments

Comments
 (0)