Skip to content

Commit 462870d

Browse files
authored
Merge pull request #10 from NoaVel/module9-task2
2 parents 3d1279f + b0191f8 commit 462870d

5 files changed

Lines changed: 190 additions & 8 deletions

File tree

index.html

Lines changed: 3 additions & 1 deletion
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>
@@ -233,8 +234,9 @@ <h2 class="success__title">Изображение успешно загруже
233234
<h2 class="data-error__title">Не удалось загрузить данные</h2>
234235
</section>
235236
</template>
237+
<script src="vendor/nouislider/nouislider.js"></script>
236238
<script src="vendor/pristine/pristine.min.js"></script>
237239
<script src="js/main.js" type="module"></script>
238-
<script src="js/functions.js"></script>
240+
<!-- <script src="js/functions.js"></script> -->
239241
</body>
240242
</html>

js/check-hashtag-validity.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ const hasValidHashtagLength = (value) =>
1515
normalizeHashtags(value).every((hashtag) => hashtag.length <= MAX_HASHTAG_LENGTH);
1616

1717
const hasValidHashtagFormat = (value) =>
18-
normalizeHashtags(value).every((hashtag) => HASHTAG_REGEXP.test(hashtag));
18+
normalizeHashtags(value).every((hashtag) =>
19+
hashtag.startsWith('#') &&
20+
hashtag.length > 1 &&
21+
HASHTAG_REGEXP.test(hashtag)
22+
);
1923

2024
const hasUniqueHashtags = (value) => {
2125
const hashtags = normalizeHashtags(value);

js/image-editor.js

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
const SCALE_STEP = 25;
2+
const MIN_SCALE = 25;
3+
const MAX_SCALE = 100;
4+
const DEFAULT_SCALE = 100;
5+
const DEFAULT_EFFECT = 'none';
6+
7+
const effectsConfig = {
8+
none: {
9+
range: { min: 0, max: 100 },
10+
start: 100,
11+
step: 1,
12+
filter: '',
13+
unit: ''
14+
},
15+
chrome: {
16+
range: { min: 0, max: 1 },
17+
start: 1,
18+
step: 0.1,
19+
filter: 'grayscale',
20+
unit: ''
21+
},
22+
sepia: {
23+
range: { min: 0, max: 1 },
24+
start: 1,
25+
step: 0.1,
26+
filter: 'sepia',
27+
unit: ''
28+
},
29+
marvin: {
30+
range: { min: 0, max: 100 },
31+
start: 100,
32+
step: 1,
33+
filter: 'invert',
34+
unit: '%'
35+
},
36+
phobos: {
37+
range: { min: 0, max: 3 },
38+
start: 3,
39+
step: 0.1,
40+
filter: 'blur',
41+
unit: 'px'
42+
},
43+
heat: {
44+
range: { min: 1, max: 3 },
45+
start: 3,
46+
step: 0.1,
47+
filter: 'brightness',
48+
unit: ''
49+
}
50+
};
51+
52+
const uploadFormNode = document.querySelector('.img-upload__form');
53+
const previewImageNode = uploadFormNode.querySelector('.img-upload__preview img');
54+
55+
const scaleValueNode = uploadFormNode.querySelector('.scale__control--value');
56+
const scaleSmallerButtonNode = uploadFormNode.querySelector('.scale__control--smaller');
57+
const scaleBiggerButtonNode = uploadFormNode.querySelector('.scale__control--bigger');
58+
59+
const effectsListNode = uploadFormNode.querySelector('.effects__list');
60+
const effectLevelNode = uploadFormNode.querySelector('.img-upload__effect-level');
61+
const effectLevelSliderNode = uploadFormNode.querySelector('.effect-level__slider');
62+
const effectLevelValueNode = uploadFormNode.querySelector('.effect-level__value');
63+
64+
const hideEffectSlider = () => {
65+
effectLevelNode.classList.add('hidden');
66+
};
67+
68+
const showEffectSlider = () => {
69+
effectLevelNode.classList.remove('hidden');
70+
};
71+
72+
const applyScale = (scaleValue) => {
73+
scaleValueNode.value = `${scaleValue}%`;
74+
previewImageNode.style.transform = `scale(${scaleValue / 100})`;
75+
};
76+
77+
const getScaleValue = () => parseInt(scaleValueNode.value, 10);
78+
79+
const getSelectedEffect = () =>
80+
uploadFormNode.querySelector('.effects__radio:checked').value;
81+
82+
const applyEffect = (effectName, effectValue) => {
83+
const currentEffect = effectsConfig[effectName];
84+
85+
if (effectName === DEFAULT_EFFECT) {
86+
previewImageNode.style.filter = '';
87+
effectLevelValueNode.value = '';
88+
hideEffectSlider();
89+
return;
90+
}
91+
92+
previewImageNode.style.filter = `${currentEffect.filter}(${effectValue}${currentEffect.unit})`;
93+
effectLevelValueNode.value = effectValue;
94+
showEffectSlider();
95+
};
96+
97+
const updateSliderOptions = (effectName) => {
98+
const currentEffect = effectsConfig[effectName];
99+
100+
effectLevelSliderNode.noUiSlider.updateOptions({
101+
range: currentEffect.range,
102+
start: currentEffect.start,
103+
step: currentEffect.step
104+
});
105+
106+
effectLevelSliderNode.noUiSlider.set(currentEffect.start);
107+
};
108+
109+
const onScaleSmallerButtonClick = () => {
110+
const newScaleValue = Math.max(getScaleValue() - SCALE_STEP, MIN_SCALE);
111+
applyScale(newScaleValue);
112+
};
113+
114+
const onScaleBiggerButtonClick = () => {
115+
const newScaleValue = Math.min(getScaleValue() + SCALE_STEP, MAX_SCALE);
116+
applyScale(newScaleValue);
117+
};
118+
119+
const onEffectsListChange = (evt) => {
120+
if (!evt.target.matches('.effects__radio')) {
121+
return;
122+
}
123+
124+
updateSliderOptions(evt.target.value);
125+
};
126+
127+
const onEffectLevelSliderUpdate = () => {
128+
const selectedEffectName = getSelectedEffect();
129+
const sliderValue = Number(effectLevelSliderNode.noUiSlider.get());
130+
131+
applyEffect(selectedEffectName, sliderValue);
132+
};
133+
134+
const resetImageEditor = () => {
135+
applyScale(DEFAULT_SCALE);
136+
uploadFormNode.querySelector('#effect-none').checked = true;
137+
previewImageNode.style.filter = '';
138+
effectLevelValueNode.value = '';
139+
hideEffectSlider();
140+
141+
effectLevelSliderNode.noUiSlider.updateOptions({
142+
range: effectsConfig[DEFAULT_EFFECT].range,
143+
start: effectsConfig[DEFAULT_EFFECT].start,
144+
step: effectsConfig[DEFAULT_EFFECT].step
145+
});
146+
147+
effectLevelSliderNode.noUiSlider.set(effectsConfig[DEFAULT_EFFECT].start);
148+
};
149+
150+
const initImageEditor = () => {
151+
applyScale(DEFAULT_SCALE);
152+
153+
if (!effectLevelSliderNode.noUiSlider) {
154+
noUiSlider.create(effectLevelSliderNode, {
155+
range: effectsConfig[DEFAULT_EFFECT].range,
156+
start: effectsConfig[DEFAULT_EFFECT].start,
157+
step: effectsConfig[DEFAULT_EFFECT].step,
158+
connect: 'lower'
159+
});
160+
161+
effectLevelSliderNode.noUiSlider.on('update', onEffectLevelSliderUpdate);
162+
}
163+
164+
hideEffectSlider();
165+
166+
scaleSmallerButtonNode.addEventListener('click', onScaleSmallerButtonClick);
167+
scaleBiggerButtonNode.addEventListener('click', onScaleBiggerButtonClick);
168+
effectsListNode.addEventListener('change', onEffectsListChange);
169+
};
170+
171+
export { initImageEditor, resetImageEditor };

js/main.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { photos } from './create-array-photos.js';
22
import { renderThumbnails } from './render-thumbnails.js';
33
import { initUploadPhotoForm } from './upload-photo-form.js';
4+
import { initImageEditor } from './image-editor.js';
45

56
renderThumbnails(photos);
67
initUploadPhotoForm();
8+
initImageEditor();
79

js/upload-photo-form.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {
55
hasUniqueHashtags
66
} from './check-hashtag-validity.js';
77

8+
import { resetImageEditor } from './image-editor.js';
9+
810
const MAX_COMMENT_LENGTH = 140;
911

1012
const bodyNode = document.body;
@@ -30,6 +32,7 @@ const resetUploadPhotoForm = () => {
3032
uploadFormNode.reset();
3133
uploadFileControl.value = '';
3234
pristine.reset();
35+
resetImageEditor();
3336
};
3437

3538
const stopEscapePropagation = (evt) => {
@@ -78,20 +81,20 @@ const onUploadFormSubmit = (evt) => {
7881

7982
pristine.addValidator(
8083
hashtagsInputNode,
81-
hasValidHashtagCount,
82-
'Нельзя указать больше пяти хэштегов'
84+
hasValidHashtagFormat,
85+
'Хэштег должен начинаться с # и содержать только буквы и цифры'
8386
);
8487

8588
pristine.addValidator(
8689
hashtagsInputNode,
87-
hasValidHashtagLength,
88-
'Максимальная длина одного хэштега — 20 символов'
90+
hasValidHashtagCount,
91+
'Нельзя указать больше пяти хэштегов'
8992
);
9093

9194
pristine.addValidator(
9295
hashtagsInputNode,
93-
hasValidHashtagFormat,
94-
'Хэштег должен начинаться с # и содержать только буквы и цифры'
96+
hasValidHashtagLength,
97+
'Максимальная длина одного хэштега — 20 символов'
9598
);
9699

97100
pristine.addValidator(

0 commit comments

Comments
 (0)