Skip to content

Commit fb77455

Browse files
authored
Merge pull request #10 from AnastasiiaXX/module9-task2
2 parents 332a8e9 + 5b6e607 commit fb77455

4 files changed

Lines changed: 134 additions & 19 deletions

File tree

index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<meta name="viewport" content="width=device-width,initial-scale=1">
66
<link rel="stylesheet" href="css/normalize.css">
77
<link rel="stylesheet" href="css/style.css">
8+
<link rel="stylesheet" href="vendor/nouislider/nouislider.css">
89
<link rel="shortcut icon" href="favicon.ico" type="image/x-icon">
910
<title>Кекстаграм</title>
1011
</head>
@@ -235,6 +236,7 @@ <h2 class="data-error__title">Не удалось загрузить данны
235236
</section>
236237
</template>
237238
<script src="vendor/pristine/pristine.min.js"></script>
239+
<script src="vendor/nouislider/nouislider.js"></script>
238240
<script src="js/main.js" type="module"></script>
239241
</body>
240242
</html>

js/image-filters.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
const EFFECTS = {
2+
chrome: { filter: 'grayscale', min: 0, max: 1, step: 0.1, unit: ''},
3+
sepia: { filter: 'sepia', min: 0, max: 1, step: 0.1, unit: ''},
4+
marvin: { filter: 'invert', min: 0, max: 100, step: 1, unit: '%'},
5+
phobos: { filter: 'blur', min: 0, max: 3, step: 0.1, unit: 'px'},
6+
heat: { filter: 'brightness', min: 1, max: 3, step: 0.1, unit: ''}
7+
};
8+
9+
const form = document.querySelector('.img-upload__form');
10+
11+
const slider = form.querySelector('.effect-level__slider');
12+
const sliderContainer = form.querySelector('.img-upload__effect-level');
13+
const uploadedImage = form.querySelector('.img-upload__preview img');
14+
const effectRadios = form.querySelectorAll('input[name="effect"]');
15+
const inputValue = form.querySelector('.effect-level__value');
16+
17+
export const initImageEffects = () => {
18+
let selectedFilter = 'none';
19+
noUiSlider.create(slider, {
20+
range: {
21+
min: 0,
22+
max: 100,
23+
},
24+
start: 50,
25+
step: 1,
26+
connect: 'lower'
27+
});
28+
29+
sliderContainer.classList.add('hidden');
30+
31+
slider.noUiSlider.on('update', () => {
32+
if (selectedFilter === 'none') {
33+
return;
34+
}
35+
const value = slider.noUiSlider.get();
36+
const effect = EFFECTS[selectedFilter];
37+
const filterStyle = `${effect.filter}(${value}${effect.unit})`;
38+
uploadedImage.style.filter = filterStyle;
39+
inputValue.value = value;
40+
});
41+
42+
effectRadios.forEach((radio) => {
43+
radio.addEventListener('change', () => {
44+
selectedFilter = radio.value;
45+
if (selectedFilter === 'none') {
46+
sliderContainer.classList.add('hidden');
47+
uploadedImage.style.filter = '';
48+
} else {
49+
sliderContainer.classList.remove('hidden');
50+
51+
const effect = EFFECTS[selectedFilter];
52+
slider.noUiSlider.updateOptions({
53+
range: { min: effect.min, max: effect.max },
54+
start: effect.max,
55+
step: effect.step
56+
});
57+
}
58+
});
59+
});
60+
};

js/image-scale.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
const form = document.querySelector('.img-upload__form');
2+
const scaleSmallerBtn = form.querySelector('.scale__control--smaller');
3+
const scaleBiggerBtn = form.querySelector('.scale__control--bigger');
4+
const scaleControlValue = form.querySelector('.scale__control--value');
5+
const uploadedImage = form.querySelector('.img-upload__preview img');
6+
7+
let currentScale = 100;
8+
export const initImageScale = () => {
9+
scaleSmallerBtn.addEventListener('click', () => {
10+
if (currentScale > 25) {
11+
currentScale -= 25;
12+
scaleControlValue.value = `${currentScale}%`;
13+
uploadedImage.style.transform = `scale(${currentScale / 100})`;
14+
}
15+
});
16+
17+
scaleBiggerBtn.addEventListener('click', () => {
18+
if (currentScale < 100) {
19+
currentScale += 25;
20+
scaleControlValue.value = `${currentScale}%`;
21+
uploadedImage.style.transform = `scale(${currentScale / 100})`;
22+
}
23+
});
24+
};

js/upload-form.js

Lines changed: 48 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { openModal, closeModal } from './modal.js';
2+
import { initImageScale } from './image-scale.js';
3+
import { initImageEffects } from './image-filters.js';
24

35
const MAX_HASHTAG_COUNT = 5;
46
const MAX_COMMENT_LENGTH = 140;
5-
const TAG_ERROR_TEXT = 'Неправильно заполнены хэштеги';
67
const HASHTAG_REGEXP = /^#[a-zа-я0-9]{1,19}$/i;
78

89
const form = document.querySelector('.img-upload__form');
@@ -23,6 +24,8 @@ const pristine = new Pristine(form, {
2324
export const initUploadForm = () => {
2425
fileInput.addEventListener('change', () => {
2526
openModal(uploadOverlay, body);
27+
initImageScale();
28+
initImageEffects();
2629
});
2730

2831
cancelBtn.addEventListener('click', () => {
@@ -31,19 +34,52 @@ export const initUploadForm = () => {
3134
fileInput.value = '';
3235
pristine.reset();
3336
});
34-
const validateTags = (value) => {
37+
38+
const stopEscPropagation = (evt) => {
39+
if (evt.key === 'Escape') {
40+
evt.stopPropagation();
41+
}
42+
};
43+
44+
const parseHashTags = (value) => {
3545
if (!value) {
36-
return true;
46+
return [];
3747
}
38-
const splitHashtags = value.split(' ').filter(Boolean);
39-
const lowerCaseHashtags = splitHashtags.map((hashtag) => hashtag.toLowerCase());
48+
return value.split(' ').filter(Boolean);
49+
};
50+
51+
const validateHashtagFormat = (value) => {
52+
const tags = parseHashTags(value);
53+
return tags.every((tag) => HASHTAG_REGEXP.test(tag));
54+
};
55+
56+
const validateHashtagCount = (value) => {
57+
const tags = parseHashTags(value);
58+
return tags.length <= MAX_HASHTAG_COUNT;
59+
};
60+
61+
const validateHashtagUnique = (value) => {
62+
const tags = parseHashTags(value);
63+
const lowerCaseHashtags = tags.map((tag) => tag.toLowerCase());
4064
const sizeUnique = new Set(lowerCaseHashtags).size;
41-
if (splitHashtags.length > MAX_HASHTAG_COUNT || splitHashtags.length !== sizeUnique) {
42-
return false;
43-
}
44-
return splitHashtags.every((hashtag) => HASHTAG_REGEXP.test(hashtag));
65+
return tags.length === sizeUnique;
4566
};
4667

68+
const hashtagValidators = [
69+
{
70+
validator: validateHashtagFormat,
71+
error: 'Хэштег должен начинаться с # и содержать только буквы и цифры, максимум 20 символов'
72+
},
73+
{
74+
validator: validateHashtagCount,
75+
error: 'Количество хэштегов не может быть больше 5'
76+
},
77+
{
78+
validator: validateHashtagUnique,
79+
error: 'Хэштеги не могут повторяться'
80+
},
81+
];
82+
4783
const validateComment = (value) => {
4884
if (!value) {
4985
return true;
@@ -52,11 +88,9 @@ export const initUploadForm = () => {
5288
return value.length <= MAX_COMMENT_LENGTH;
5389
};
5490

55-
pristine.addValidator(
56-
hashtagInput,
57-
validateTags,
58-
TAG_ERROR_TEXT
59-
);
91+
hashtagValidators.forEach((rule) => {
92+
pristine.addValidator(hashtagInput, rule.validator, rule.error);
93+
});
6094

6195
pristine.addValidator(
6296
commentInput,
@@ -72,11 +106,6 @@ export const initUploadForm = () => {
72106
}
73107
});
74108

75-
const stopEscPropagation = (evt) => {
76-
if (evt.key === 'Escape') {
77-
evt.stopPropagation();
78-
}
79-
};
80109
hashtagInput.addEventListener('keydown', stopEscPropagation);
81110
commentInput.addEventListener('keydown', stopEscPropagation);
82111
};

0 commit comments

Comments
 (0)