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;