From fc5de892d25369ba36a75d754042e6e20ab2bd2a Mon Sep 17 00:00:00 2001 From: Vlad Possin Date: Wed, 23 Dec 2020 18:45:22 +0600 Subject: [PATCH] created homework_6 --- projects/dnd/dnd.html | 9 +++ projects/dnd/functions.js | 90 ++++++++++++++++++++++++++++ projects/dnd/functions.spec.js | 106 +++++++++++++++++++++++++++++++++ projects/dnd/index.js | 64 ++++++++++++++++++++ projects/dnd/index.spec.js | 38 ++++++++++++ 5 files changed, 307 insertions(+) create mode 100644 projects/dnd/dnd.html create mode 100644 projects/dnd/functions.js create mode 100644 projects/dnd/functions.spec.js create mode 100644 projects/dnd/index.js create mode 100644 projects/dnd/index.spec.js diff --git a/projects/dnd/dnd.html b/projects/dnd/dnd.html new file mode 100644 index 0000000..964c99c --- /dev/null +++ b/projects/dnd/dnd.html @@ -0,0 +1,9 @@ + + +
+ +
\ No newline at end of file diff --git a/projects/dnd/functions.js b/projects/dnd/functions.js new file mode 100644 index 0000000..df16aac --- /dev/null +++ b/projects/dnd/functions.js @@ -0,0 +1,90 @@ +/* ДЗ 6 - DOM Events */ + +/* + Задание 1: + + Функция должна добавлять обработчик fn события eventName к элементу target + + Пример: + addListener('click', document.querySelector('a'), () => console.log('...')) // должна добавить указанный обработчик кликов на указанный элемент + */ +function addListener(eventName, target, fn) { + target.addEventListener(eventName, fn); +} + +/* + Задание 2: + + Функция должна удалять у элемента target обработчик fn события eventName + + Пример: + removeListener('click', document.querySelector('a'), someHandler) // должна удалить указанный обработчик кликов на указанный элемент + */ +function removeListener(eventName, target, fn) { + target.removeEventListener(eventName, fn); +} + +/* + Задание 3: + + Функция должна добавить к элементу target такой обработчик на события eventName, чтобы он отменял действия по умолчанию + + Пример: + skipDefault('click', document.querySelector('a')) // после вызова функции, клики на указанную ссылку не должны приводить к переходу на другую страницу + */ +function skipDefault(eventName, target) { + target.addEventListener(eventName, (e) => { + e.preventDefault(); + }); +} + +/* + Задание 4: + + Функция должна эмулировать событие click для элемента target + + Пример: + emulateClick(document.querySelector('a')) // для указанного элемента должно быть симулировано события click + */ +function emulateClick(target) { + const event = new Event('click'); + target.dispatchEvent(event); +} + +/* + Задание 6: + + Функция должна добавить такой обработчик кликов к элементу target, + который реагирует (вызывает fn) только на клики по элементам BUTTON внутри target + + Пример: + delegate(document.body, () => console.log('кликнули на button')) // добавит такой обработчик кликов для body, который будет вызывать указанную функцию только если кликнули на кнопку (элемент с тегом button) + */ +function delegate(target, fn) { + target.addEventListener('click', (e) => { + if (e.target.tagName === 'BUTTON') { + fn(); + } + }); +} + +/* + Задание 7: + + Функция должна добавить такой обработчик кликов к элементу target, + который сработает только один раз и удалится (перестанет срабатывать для последующих кликов по указанному элементу) + + Пример: + once(document.querySelector('button'), () => console.log('обработчик выполнился!')) // добавит такой обработчик кликов для указанного элемента, который вызовется только один раз и затем удалится + */ +function once(target, fn) { + let done = false; + target.addEventListener('click', () => { + if (!done) { + fn(); + done = true; + } + }); +} + +export { addListener, removeListener, skipDefault, emulateClick, delegate, once }; diff --git a/projects/dnd/functions.spec.js b/projects/dnd/functions.spec.js new file mode 100644 index 0000000..bbb2f07 --- /dev/null +++ b/projects/dnd/functions.spec.js @@ -0,0 +1,106 @@ +import { + addListener, + delegate, + emulateClick, + once, + removeListener, + skipDefault, +} from './functions'; + +describe('ДЗ 5.1 - DOM Events', () => { + describe('addListener', () => { + it('должна добавлять обработчик событий элемента', () => { + const target = document.createElement('div'); + const eventName = 'click'; + const fn = jest.fn(); + + addListener(eventName, target, fn); + + target.dispatchEvent(new CustomEvent(eventName)); + expect(fn).toBeCalled(); + }); + }); + + describe('removeListener', () => { + it('должна удалять обработчик событий элемента', () => { + const target = document.createElement('div'); + const eventName = 'click'; + const fn = jest.fn(); + + target.addEventListener(eventName, fn); + + removeListener(eventName, target, fn); + + target.dispatchEvent(new CustomEvent(eventName)); + expect(fn).not.toBeCalled(); + }); + }); + + describe('skipDefault', () => { + it('должна добавлять такой обработчик, который предотвращает действие по умолчанию', () => { + const target = document.createElement('div'); + const eventName = 'click'; + + skipDefault(eventName, target); + + const result = target.dispatchEvent( + new CustomEvent(eventName, { cancelable: true }) + ); + expect(!result); + }); + }); + + describe('emulateClick', () => { + it('должна эмулировать клик по элементу', () => { + const target = document.createElement('div'); + const eventName = 'click'; + const fn = jest.fn(); + + target.addEventListener(eventName, fn); + + emulateClick(target); + + expect(fn).toBeCalled(); + }); + }); + + describe('delegate', () => { + it('должна добавлять обработчик кликов, который реагирует только на клики по кнопкам', () => { + const target = document.createElement('div'); + const eventName = 'click'; + const fn = jest.fn(); + + target.innerHTML = '

'; + + delegate(target, fn); + + expect(fn).not.toBeCalled(); + target.children[0].dispatchEvent(new CustomEvent(eventName, { bubbles: true })); + expect(fn).not.toBeCalled(); + target.children[1].dispatchEvent(new CustomEvent(eventName, { bubbles: true })); + expect(fn).not.toBeCalled(); + target.children[2].dispatchEvent(new CustomEvent(eventName, { bubbles: true })); + expect(fn).not.toBeCalled(); + target.children[3].dispatchEvent(new CustomEvent(eventName, { bubbles: true })); + expect(fn).toBeCalled(); + }); + }); + + describe('once', () => { + it('должна добавлять обработчик кликов, который сработает только один раз и удалится', () => { + const target = document.createElement('div'); + const eventName = 'click'; + let passed = 0; + const fn = () => passed++; + + once(target, fn); + + expect(passed).toBe(0); + target.dispatchEvent(new CustomEvent(eventName)); + expect(passed).toBe(1); + target.dispatchEvent(new CustomEvent(eventName)); + expect(passed).toBe(1); + target.dispatchEvent(new CustomEvent(eventName)); + }); + }); +}); diff --git a/projects/dnd/index.js b/projects/dnd/index.js new file mode 100644 index 0000000..29e66db --- /dev/null +++ b/projects/dnd/index.js @@ -0,0 +1,64 @@ +/* Задание со звездочкой */ + +/* + Создайте страницу с кнопкой. + При нажатии на кнопку должен создаваться div со случайными размерами, цветом и позицией на экране + Необходимо предоставить возможность перетаскивать созданные div при помощи drag and drop + Запрещено использовать сторонние библиотеки. Разрешено пользоваться только тем, что встроено в браузер + */ + +/* + homeworkContainer - это контейнер для всех ваших домашних заданий + Если вы создаете новые html-элементы и добавляете их на страницу, то добавляйте их только в этот контейнер + + Пример: + const newDiv = document.createElement('div'); + homeworkContainer.appendChild(newDiv); + */ +import './dnd.html'; + +const homeworkContainer = document.querySelector('#app'); + +function random(from, to) { + return parseInt(from + Math.random() * to - from); +} + +let isDrag; +let firstpos_x = 0; +let firstpos_y = 0; + +document.addEventListener('mousemove', (e) => { + if (isDrag) { + isDrag.style.top = e.clientY - firstpos_x + 'px'; + isDrag.style.left = e.clientX - firstpos_y + 'px'; + } +}); + +export function createDiv() { + const div = document.createElement('div'); + const minSize = 20; + const maxSize = 200; + const maxColor = 0xffffff; + + div.className = 'draggable-div'; + div.style.background = '#' + random(0, maxColor).toString(16); + div.style.top = random(0, window.innerHeight) + 'px'; + div.style.left = random(0, window.innerWidth) + 'px'; + div.style.width = random(minSize, maxSize) + 'px'; + div.style.height = random(minSize, maxSize) + 'px'; + + div.addEventListener('mousedown', (e) => { + isDrag = div; + firstpos_x = e.offsetX; + firstpos_y = e.offsetY; + }); + div.addEventListener('mouseup', () => (isDrag = false)); + return div; +} + +const addDivButton = homeworkContainer.querySelector('#addDiv'); + +addDivButton.addEventListener('click', function () { + const div = createDiv(); + homeworkContainer.append(div); +}); diff --git a/projects/dnd/index.spec.js b/projects/dnd/index.spec.js new file mode 100644 index 0000000..6650373 --- /dev/null +++ b/projects/dnd/index.spec.js @@ -0,0 +1,38 @@ +describe('ДЗ 5.2 - Div D&D', () => { + const dndPage = require('./index'); + const homeworkContainer = document.querySelector('#app'); + let addDivButton; + + describe('Функциональное тестирование', () => { + describe('createDiv', () => { + it('должна создавать div с произвольными размерами/позицией/цветом', () => { + const result = dndPage.createDiv(); + + expect(result).toBeInstanceOf(Element); + expect(result.tagName).toBe('DIV'); + expect(result.style.backgroundColor || result.style.background).not.toBe(''); + expect(result.style.top).not.toBe(''); + expect(result.style.left).not.toBe(''); + expect(result.style.width).not.toBe(''); + expect(result.style.height).not.toBe(''); + }); + }); + }); + + describe('Интеграционное тестирование', () => { + it('на старнице должна быть кнопка с id addDiv', () => { + addDivButton = homeworkContainer.querySelector('#addDiv'); + expect(addDivButton).toBeInstanceOf(Element); + expect(addDivButton.tagName).toBe('BUTTON'); + }); + + it('создавать div с классом draggable-div при клике на кнопку', () => { + const divsCount = homeworkContainer.querySelectorAll('.draggable-div').length; + + addDivButton.dispatchEvent(new MouseEvent('click', { view: window })); + const newDivsCount = homeworkContainer.querySelectorAll('.draggable-div').length; + + expect(newDivsCount - divsCount).toBe(1); + }); + }); +});