diff --git a/async-requests/poll/task.js b/async-requests/poll/task.js
index e69de29bb2..00896edd11 100644
--- a/async-requests/poll/task.js
+++ b/async-requests/poll/task.js
@@ -0,0 +1,61 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const pollTitle = document.getElementById('poll__title');
+ const pollAnswers = document.getElementById('poll__answers');
+
+ function renderPoll(pollData) {
+ pollTitle.textContent = pollData.data.title;
+ pollAnswers.innerHTML = '';
+ pollData.data.answers.forEach((answer, index) => {
+ const answerButton = document.createElement('button');
+ answerButton.classList.add('poll__answer');
+ answerButton.textContent = answer;
+ answerButton.addEventListener('click', function() {
+ sendVote(pollData.id, index);
+ });
+ pollAnswers.appendChild(answerButton);
+ });
+ }
+
+ function sendVote(pollId, answerIndex) {
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', 'https://students.netoservices.ru/nestjs-backend/poll');
+ xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
+ xhr.onload = function() {
+ if (xhr.status === 200) {
+ const response = JSON.parse(xhr.responseText);
+ showThankYou();
+ console.log(response);
+ } else {
+ console.error('Error sending vote:', xhr.status);
+ }
+ };
+ xhr.onerror = function() {
+ console.error('Error sending vote:', xhr.status);
+ };
+ const params = `vote=${pollId}&answer=${answerIndex}`;
+ xhr.send(params);
+ }
+
+ function showThankYou() {
+ alert('Спасибо, ваш голос засчитан!');
+ }
+
+ function loadPoll() {
+ const xhr = new XMLHttpRequest();
+ xhr.open('GET', 'https://students.netoservices.ru/nestjs-backend/poll');
+ xhr.onload = function() {
+ if (xhr.status === 200) {
+ const pollData = JSON.parse(xhr.responseText);
+ renderPoll(pollData);
+ } else {
+ console.error('Error loading poll:', xhr.status);
+ }
+ };
+ xhr.onerror = function() {
+ console.error('Error loading poll:', xhr.status);
+ };
+ xhr.send();
+ }
+
+ loadPoll();
+});
diff --git a/async-requests/preloader/task.js b/async-requests/preloader/task.js
index e69de29bb2..da2fa83002 100644
--- a/async-requests/preloader/task.js
+++ b/async-requests/preloader/task.js
@@ -0,0 +1,53 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const loader = document.getElementById('loader');
+ const items = document.getElementById('items');
+
+ function showLoader() {
+ loader.classList.add('loader_active');
+ }
+
+ function hideLoader() {
+ loader.classList.remove('loader_active');
+ }
+
+ function renderCurrency(currency) {
+ const item = document.createElement('div');
+ item.classList.add('item');
+
+ const code = document.createElement('div');
+ code.classList.add('item__code');
+ code.textContent = currency.CharCode;
+ item.appendChild(code);
+
+ const value = document.createElement('div');
+ value.classList.add('item__value');
+ value.textContent = currency.Value;
+ item.appendChild(value);
+
+ const currencyText = document.createElement('div');
+ currencyText.classList.add('item__currency');
+ currencyText.textContent = 'руб.';
+ item.appendChild(currencyText);
+
+ items.appendChild(item);
+ }
+
+ function loadCurrency() {
+ showLoader();
+ fetch('https://students.netoservices.ru/nestjs-backend/slow-get-courses')
+ .then(response => response.json())
+ .then(data => {
+ hideLoader();
+ const currencies = data.response.Valute;
+ for (const currency in currencies) {
+ renderCurrency(currencies[currency]);
+ }
+ })
+ .catch(error => {
+ console.error('Error fetching currency:', error);
+ hideLoader();
+ });
+ }
+
+ loadCurrency();
+});
diff --git a/async-requests/progressbar/task.js b/async-requests/progressbar/task.js
index e69de29bb2..3648c5736f 100644
--- a/async-requests/progressbar/task.js
+++ b/async-requests/progressbar/task.js
@@ -0,0 +1,36 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const progress = document.getElementById('progress');
+
+ function updateProgress(event) {
+ if (event.lengthComputable) {
+ const percentComplete = (event.loaded / event.total) * 100;
+ progress.value = percentComplete;
+ }
+ }
+
+ function sendFormData(formData) {
+ const xhr = new XMLHttpRequest();
+ xhr.open('POST', 'https://students.netoservices.ru/nestjs-backend/upload');
+ xhr.upload.addEventListener('progress', updateProgress);
+ xhr.onload = function() {
+ if (xhr.status === 200) {
+ console.log('File uploaded successfully');
+ } else {
+ console.error('Error uploading file:', xhr.status);
+ }
+ };
+ xhr.onerror = function() {
+ console.error('Error uploading file:', xhr.status);
+ };
+ xhr.send(formData);
+ }
+
+ function handleFormSubmit(event) {
+ event.preventDefault();
+ const formData = new FormData(event.target);
+ sendFormData(formData);
+ }
+
+ const form = document.getElementById('form');
+ form.addEventListener('submit', handleFormSubmit);
+});
diff --git a/document-structure/cart/task.js b/document-structure/cart/task.js
index e69de29bb2..28b3b33860 100644
--- a/document-structure/cart/task.js
+++ b/document-structure/cart/task.js
@@ -0,0 +1,52 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const productCards = document.querySelectorAll('.product');
+ const cart = document.querySelector('.cart');
+ const cartTitle = document.querySelector('.cart__title');
+
+ productCards.forEach(product => {
+ const addButton = product.querySelector('.product__quantity-control_inc');
+ const removeButton = product.querySelector('.product__quantity-control_dec');
+ const quantityValue = product.querySelector('.product__quantity-value');
+ const addToCartButton = product.querySelector('.product__add');
+
+ addButton.addEventListener('click', function() {
+ let newValue = parseInt(quantityValue.textContent) + 1;
+ quantityValue.textContent = newValue > 0 ? newValue : 1;
+ });
+
+ removeButton.addEventListener('click', function() {
+ let newValue = parseInt(quantityValue.textContent) - 1;
+ quantityValue.textContent = newValue > 0 ? newValue : 1;
+ });
+
+ addToCartButton.addEventListener('click', function() {
+ const productId = product.getAttribute('data-id');
+ const productImageSrc = product.querySelector('.product__image').getAttribute('src');
+ const productQuantity = parseInt(quantityValue.textContent);
+
+ const existingCartItem = cart.querySelector(`.cart__product[data-id="${productId}"]`);
+ if (existingCartItem) {
+ const existingQuantity = parseInt(existingCartItem.querySelector('.cart__product-count').textContent);
+ existingCartItem.querySelector('.cart__product-count').textContent = existingQuantity + productQuantity;
+ } else {
+ const cartProduct = document.createElement('div');
+ cartProduct.classList.add('cart__product');
+ cartProduct.setAttribute('data-id', productId);
+
+ const cartProductImage = document.createElement('img');
+ cartProductImage.classList.add('cart__product-image');
+ cartProductImage.setAttribute('src', productImageSrc);
+ cartProduct.appendChild(cartProductImage);
+
+ const cartProductCount = document.createElement('div');
+ cartProductCount.classList.add('cart__product-count');
+ cartProductCount.textContent = productQuantity;
+ cartProduct.appendChild(cartProductCount);
+ cart.appendChild(cartProduct);
+ }
+
+ cartTitle.style.display = 'block';
+ });
+ });
+ });
+
\ No newline at end of file
diff --git a/document-structure/todo/task.js b/document-structure/todo/task.js
index e69de29bb2..0a3d77a5ae 100644
--- a/document-structure/todo/task.js
+++ b/document-structure/todo/task.js
@@ -0,0 +1,32 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const taskList = document.getElementById('tasks__list');
+ const inputTask = document.getElementById('task__input');
+ const addButton = document.getElementById('tasks__add');
+
+ function addTask(taskContent) {
+ const taskHTML = `
+
+
+ ${taskContent}
+
+
×
+
+ `;
+ taskList.insertAdjacentHTML('beforeend', taskHTML);
+
+ const removeButtons = taskList.querySelectorAll('.task__remove');
+ const lastRemoveButton = removeButtons[removeButtons.length - 1];
+ lastRemoveButton.addEventListener('click', function() {
+ lastRemoveButton.parentElement.remove();
+ });
+ }
+
+ addButton.addEventListener('click', function(event) {
+ event.preventDefault();
+ if (inputTask.value.trim() !== '') {
+ addTask(inputTask.value.trim());
+ inputTask.value = '';
+ }
+ });
+ });
+
\ No newline at end of file
diff --git a/document-structure/tooltip/task.js b/document-structure/tooltip/task.js
index e69de29bb2..b10d99df5a 100644
--- a/document-structure/tooltip/task.js
+++ b/document-structure/tooltip/task.js
@@ -0,0 +1,33 @@
+document.addEventListener('DOMContentLoaded', function() {
+ let currentTooltip = null;
+
+ document.querySelectorAll('.has-tooltip').forEach(tooltip => {
+ tooltip.addEventListener('click', function(event) {
+ event.preventDefault();
+ const tooltipText = this.getAttribute('title');
+
+ if (currentTooltip) {
+ currentTooltip.remove();
+ }
+
+ currentTooltip = document.createElement('div');
+ currentTooltip.classList.add('tooltip');
+ currentTooltip.textContent = tooltipText;
+ document.body.appendChild(currentTooltip);
+ positionTooltip(this, currentTooltip);
+ });
+ });
+
+ function positionTooltip(tooltipTrigger, tooltipElement) {
+ const tooltipRect = tooltipElement.getBoundingClientRect();
+ const triggerRect = tooltipTrigger.getBoundingClientRect();
+ const bodyRect = document.body.getBoundingClientRect();
+
+ const top = triggerRect.top - tooltipRect.height - 5;
+ const left = triggerRect.left + (triggerRect.width - tooltipRect.width) / 2;
+
+ tooltipElement.style.top = `${Math.max(top, bodyRect.top)}px`;
+ tooltipElement.style.left = `${Math.max(left, bodyRect.left)}px`;
+ }
+ });
+
diff --git a/dom/ads/task.js b/dom/ads/task.js
index e69de29bb2..a2e8041c11 100644
--- a/dom/ads/task.js
+++ b/dom/ads/task.js
@@ -0,0 +1,29 @@
+class AdRotator {
+ constructor() {
+ this.rotatorElements = document.querySelectorAll('.rotator__case');
+ this.currentIndex = 0;
+ this.startRotation();
+ }
+
+ startRotation() {
+ this.intervalId = setInterval(() => {
+ this.rotate();
+ }, 1000); // Меняем текст каждую секунду
+ }
+
+ rotate() {
+ const currentElement = this.rotatorElements[this.currentIndex];
+ currentElement.classList.remove('rotator__case_active');
+
+ this.currentIndex++;
+ if (this.currentIndex >= this.rotatorElements.length) {
+ this.currentIndex = 0; // Возвращаемся к первому элементу после прохождения всех
+ }
+
+ const nextElement = this.rotatorElements[this.currentIndex];
+ nextElement.classList.add('rotator__case_active');
+ }
+ }
+
+ new AdRotator();
+
\ No newline at end of file
diff --git a/dom/book-reader/task.js b/dom/book-reader/task.js
index e69de29bb2..299233429e 100644
--- a/dom/book-reader/task.js
+++ b/dom/book-reader/task.js
@@ -0,0 +1,17 @@
+const fontSizeSwitches = document.querySelectorAll('.font-size');
+const book = document.querySelector('#book');
+
+fontSizeSwitches.forEach(fontSizeSwitch => {
+ fontSizeSwitch.addEventListener("click", (event) => {
+ event.preventDefault();
+ const currentFontSize = document.querySelector('.font-size_active');
+ currentFontSize.classList.remove('font-size_active');
+ event.target.classList.add('font-size_active');
+ changeFont(event.target.dataset.size);
+ })
+});
+
+function changeFont(fontSize) {
+ book.className = `book ${fontSize ? `book_fs-${fontSize}` : ''}`;
+}
+
diff --git a/dom/reveal/task.js b/dom/reveal/task.js
index e69de29bb2..c9ad830aed 100644
--- a/dom/reveal/task.js
+++ b/dom/reveal/task.js
@@ -0,0 +1,36 @@
+class RevealOnScroll {
+ constructor() {
+ this.revealElements = document.querySelectorAll('.reveal');
+ this.scrollHandler = this.handleScroll.bind(this);
+
+ this.registerEvents();
+ this.handleScroll(); // Вызываем метод handleScroll при инициализации, чтобы показать блоки, которые уже находятся в области видимости
+ }
+
+ registerEvents() {
+ window.addEventListener('scroll', this.scrollHandler);
+ }
+
+ handleScroll() {
+ this.revealElements.forEach(element => {
+ if (this.isElementInViewport(element)) {
+ element.classList.add('reveal_active');
+ } else {
+ element.classList.remove('reveal_active');
+ }
+ });
+ }
+
+ isElementInViewport(el) {
+ const rect = el.getBoundingClientRect();
+ return (
+ rect.top >= 0 &&
+ rect.left >= 0 &&
+ rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
+ rect.right <= (window.innerWidth || document.documentElement.clientWidth)
+ );
+ }
+ }
+
+ new RevealOnScroll();
+
\ No newline at end of file
diff --git a/event-object/dropdown/task.js b/event-object/dropdown/task.js
index e69de29bb2..f21bbc4603 100644
--- a/event-object/dropdown/task.js
+++ b/event-object/dropdown/task.js
@@ -0,0 +1,23 @@
+document.addEventListener('DOMContentLoaded', function() {
+ const dropdowns = document.querySelectorAll('.dropdown');
+
+ dropdowns.forEach(function(dropdown) {
+ const valueElement = dropdown.querySelector('.dropdown__value');
+ const listElement = dropdown.querySelector('.dropdown__list');
+
+ valueElement.addEventListener('click', function() {
+ listElement.classList.toggle('dropdown__list_active');
+ });
+
+ const items = listElement.querySelectorAll('.dropdown__item');
+ items.forEach(function(item) {
+ item.addEventListener('click', function(event) {
+ event.preventDefault(); // Предотвращаем переход по ссылке
+
+ const newValue = item.querySelector('.dropdown__link').textContent;
+ valueElement.textContent = newValue;
+ listElement.classList.remove('dropdown__list_active');
+ });
+ });
+ });
+});
diff --git a/event-object/keysolo/task.js b/event-object/keysolo/task.js
index ffbc30fbb8..a96eb850af 100644
--- a/event-object/keysolo/task.js
+++ b/event-object/keysolo/task.js
@@ -17,18 +17,20 @@ class Game {
}
registerEvents() {
- /*
- TODO:
- Написать обработчик события, который откликается
- на каждый введённый символ.
- В случае правильного ввода символа вызываем this.success()
- При неправильном вводе символа - this.fail();
- DOM-элемент текущего символа находится в свойстве this.currentSymbol.
- */
+ document.addEventListener('keydown', (event) => {
+ const pressedKey = event.key.toLowerCase();
+ const currentSymbol = this.currentSymbol.textContent.toLowerCase();
+
+ if (pressedKey === currentSymbol) {
+ this.success();
+ } else {
+ this.fail();
+ }
+ });
}
success() {
- if(this.currentSymbol.classList.contains("symbol_current")) this.currentSymbol.classList.remove("symbol_current");
+ if (this.currentSymbol.classList.contains('symbol_current')) this.currentSymbol.classList.remove('symbol_current');
this.currentSymbol.classList.add('symbol_correct');
this.currentSymbol = this.currentSymbol.nextElementSibling;
@@ -54,41 +56,36 @@ class Game {
setNewWord() {
const word = this.getWord();
-
this.renderWord(word);
}
getWord() {
const words = [
- 'bob',
- 'awesome',
- 'netology',
- 'hello',
- 'kitty',
- 'rock',
- 'youtube',
- 'popcorn',
- 'cinema',
- 'love',
- 'javascript'
- ],
- index = Math.floor(Math.random() * words.length);
-
+ 'bob',
+ 'awesome',
+ 'netology',
+ 'hello',
+ 'kitty',
+ 'rock',
+ 'youtube',
+ 'popcorn',
+ 'cinema',
+ 'love',
+ 'javascript'
+ ];
+ const index = Math.floor(Math.random() * words.length);
return words[index];
}
renderWord(word) {
const html = [...word]
- .map(
- (s, i) =>
- `${s}`
- )
+ .map((s, i) => `${s}`)
.join('');
this.wordElement.innerHTML = html;
-
this.currentSymbol = this.wordElement.querySelector('.symbol_current');
}
}
-new Game(document.getElementById('game'))
+new Game(document.getElementById('game'));
+
diff --git a/event-object/tabs/task.js b/event-object/tabs/task.js
index e69de29bb2..26a75abd8b 100644
--- a/event-object/tabs/task.js
+++ b/event-object/tabs/task.js
@@ -0,0 +1,32 @@
+class Tabs {
+ constructor(container) {
+ this.container = container;
+ this.tabs = container.querySelectorAll('.tab');
+ this.tabContents = container.querySelectorAll('.tab__content');
+
+ this.registerEvents();
+ }
+
+ registerEvents() {
+ this.tabs.forEach(tab => {
+ tab.addEventListener('click', () => {
+ this.activateTab(tab);
+ });
+ });
+ }
+
+ activateTab(selectedTab) {
+ if (!selectedTab || !selectedTab.classList) return;
+ this.tabs.forEach(tab => tab.classList.remove('tab_active'));
+ this.tabContents.forEach(content => content.classList.remove('tab__content_active'));
+
+ selectedTab.classList.add('tab_active');
+ const index = Array.from(this.tabs).indexOf(selectedTab);
+ const content = this.container.querySelectorAll('.tab__content')[index];
+ if (content) {
+ content.classList.add('tab__content_active');
+ }
+ }
+}
+
+new Tabs(document.getElementById('tabs1'));
diff --git a/js-features/cookie-clicker/task.js b/js-features/cookie-clicker/task.js
index e69de29bb2..843eaac86f 100644
--- a/js-features/cookie-clicker/task.js
+++ b/js-features/cookie-clicker/task.js
@@ -0,0 +1,24 @@
+let clickCount = 0;
+const cookieElement = document.getElementById('cookie');
+const clickCountElement = document.getElementById('click-count');
+let lastClickTime = new Date();
+
+cookieElement.addEventListener('click', () => {
+ clickCount++;
+ clickCountElement.innerText = `Количество кликов: ${clickCount}`;
+
+ const currentTime = new Date();
+ const timeDifference = (currentTime - lastClickTime) / 1000;
+ const clickSpeed = 1 / timeDifference;
+ document.getElementById('click-speed').innerText = `Скорость клика: ${clickSpeed.toFixed(2)} кликов в секунду`;
+
+ lastClickTime = currentTime;
+
+ if (clickCount % 2 === 0) {
+ cookieElement.style.width = '100px';
+ cookieElement.style.height = '100px';
+ } else {
+ cookieElement.style.width = '80px';
+ cookieElement.style.height = '80px';
+ }
+});
diff --git a/js-features/countdown/task.js b/js-features/countdown/task.js
index e69de29bb2..7159ce0c00 100644
--- a/js-features/countdown/task.js
+++ b/js-features/countdown/task.js
@@ -0,0 +1,28 @@
+document.addEventListener('DOMContentLoaded', function () {
+
+ let seconds = 600;
+
+ function formatTime(seconds) {
+ const hours = Math.floor(seconds / 3600);
+ const minutes = Math.floor((seconds % 3600) / 60);
+ const remainingSeconds = seconds % 60;
+
+ const formattedTime = `${String(hours).padStart(2, '0')}:${String(minutes).padStart(2, '0')}:${String(remainingSeconds).padStart(2, '0')}`;
+ return formattedTime;
+ }
+
+ function updateTimer() {
+ if (seconds > 0) {
+ seconds--;
+
+ document.getElementById('timer').textContent = formatTime(seconds);
+
+ setTimeout(updateTimer, 1000);
+ } else {
+ alert('Вы победили в конкурсе!');
+ }
+ }
+
+ updateTimer();
+ });
+
\ No newline at end of file
diff --git a/js-features/mole-game/task.js b/js-features/mole-game/task.js
index e69de29bb2..c87abcf545 100644
--- a/js-features/mole-game/task.js
+++ b/js-features/mole-game/task.js
@@ -0,0 +1,45 @@
+let score = 0;
+let fails = 0;
+let scoreDisplay = document.getElementById('score');
+let failsDisplay = document.getElementById('fails'); // Переменная для отображения количества промахов
+
+function getHole(index) {
+ return document.getElementById(`hole${index}`);
+}
+
+function startGame() {
+ score = 0;
+ fails = 0;
+ scoreDisplay.textContent = score;
+ failsDisplay.textContent = fails; // Отображение количества промахов
+
+ for (let i = 1; i <= 9; i++) {
+ getHole(i).addEventListener('click', onHoleClick);
+ }
+}
+
+function onHoleClick(event) {
+ if (event.target.classList.contains('hole_has-mole')) {
+ score++;
+ scoreDisplay.textContent = score;
+ if (score === 10) {
+ alert('Вы выиграли!');
+ endGame();
+ }
+ } else {
+ fails++;
+ failsDisplay.textContent = fails; // Обновляем отображение количества промахов
+ if (fails === 5) {
+ alert('Игра завершена. Вы проиграли.');
+ endGame();
+ }
+ }
+}
+
+function endGame() {
+ for (let i = 1; i <= 9; i++) {
+ getHole(i).removeEventListener('click', onHoleClick);
+ }
+}
+
+window.onload = startGame;