diff --git a/projects/dom/index.js b/projects/dom/index.js new file mode 100644 index 000000000..ebfe1e02f --- /dev/null +++ b/projects/dom/index.js @@ -0,0 +1,164 @@ +/* ДЗ 4 - работа с DOM */ + +/* + Задание 1: + + 1.1: Функция должна создать элемент с тегом DIV + + 1.2: В созданный элемент необходимо поместить текст, переданный в параметр text + + Пример: + createDivWithText('loftschool') // создаст элемент div, поместит в него 'loftschool' и вернет созданный элемент + */ +function createDivWithText(text) { + const element = document.createElement('div'); + element.textContent = text; + return element; +} + +/* + Задание 2: + + Функция должна вставлять элемент, переданный в параметре what в начало элемента, переданного в параметре where + + Пример: + prepend(document.querySelector('#one'), document.querySelector('#two')) // добавит элемент переданный первым аргументом в начало элемента переданного вторым аргументом + */ +function prepend(what, where) { + return where.prepend(what); +} + +/* + Задание 3: + + 3.1: Функция должна перебрать все дочерние элементы узла, переданного в параметре where + + 3.2: Функция должна вернуть массив, состоящий из тех дочерних элементов следующим соседом которых является элемент с тегом P + + Пример: + Представим, что есть разметка: + +
+

+ + +

+ + + findAllPSiblings(document.body) // функция должна вернуть массив с элементами div и span т.к. следующим соседом этих элементов является элемент с тегом P + */ +function findAllPSiblings(where) { + const array = []; + for (let i = 0; i < where.children.length; i++) { + if (where.children[i].tagName === 'P') { + array.push(where.children[i].previousElementSibling); + } + } + return array; +} + +/* + Задание 4: + + Функция представленная ниже, перебирает все дочерние узлы типа "элемент" внутри узла переданного в параметре where и возвращает массив из текстового содержимого найденных элементов + Но похоже, что в код функции закралась ошибка и она работает не так, как описано. + + Необходимо найти и исправить ошибку в коде так, чтобы функция работала так, как описано выше. + + Пример: + Представим, что есть разметка: + +
привет
+
loftschool
+ + + findError(document.body) // функция должна вернуть массив с элементами 'привет' и 'loftschool' + */ +function findError(where) { + const result = []; + + for (const child of where.children) { + result.push(child.textContent); + } + + return result; +} + +/* + Задание 5: + + Функция должна перебрать все дочерние узлы элемента переданного в параметре where и удалить из него все текстовые узлы + + Задачу необходимо решить без использования рекурсии, то есть можно не уходить вглубь дерева. + Так же будьте внимательны при удалении узлов, т.к. можно получить неожиданное поведение при переборе узлов + + Пример: + После выполнения функции, дерево
привет

loftchool!!! + должно быть преобразовано в

+ */ +function deleteTextNodes(where) { + for (const child of where.childNodes) { + if (child.nodeType === 3) { + child.parentNode.removeChild(child); + } + } + + return where.childNodes; +} + +/* + Задание 6 *: + + Необходимо собрать статистику по всем узлам внутри элемента переданного в параметре root и вернуть ее в виде объекта + Статистика должна содержать: + - количество текстовых узлов + - количество элементов каждого класса + - количество элементов каждого тега + Для работы с классами рекомендуется использовать classList + Постарайтесь не создавать глобальных переменных + + Пример: + Для дерева
привет! loftschool
+ должен быть возвращен такой объект: + { + tags: { DIV: 1, B: 2}, + classes: { "some-class-1": 2, "some-class-2": 1 }, + texts: 3 + } + */ +function collectDOMStat(root) { + const result = { + tags: {}, + classes: {}, + texts: 0, + }; + + for (const child of root.childNodes) { + if (child.nodeType === 3) { + result.texts++; + } else if (child.nodeType === 1) { + if (child.tagName in result.tags) { + result.tags[child.tagName]++; + } else { + result.tags[child.tagName] = 1; + } + for (const className of child.classList) { + if (className in result.classes) { + result.classes[className]++; + } else { + result.classes[className] = 1; + } + } + } + } + return result; +} + +export { + createDivWithText, + prepend, + findAllPSiblings, + findError, + deleteTextNodes, + collectDOMStat, +}; diff --git a/projects/dom/index.spec.js b/projects/dom/index.spec.js new file mode 100644 index 000000000..3d85e7c67 --- /dev/null +++ b/projects/dom/index.spec.js @@ -0,0 +1,112 @@ +import { randomValue } from '../../scripts/helper'; +import { + collectDOMStat, + createDivWithText, + deleteTextNodes, + findAllPSiblings, + findError, + prepend, +} from './index'; + +function random(type) { + const result = randomValue(type); + + if (type === 'string') { + return encodeURIComponent(result); + } + + return result; +} + +describe('ДЗ 4 - Работа с DOM', () => { + describe('createDivWithText', () => { + it('должна возвращать элемент с тегом DIV', () => { + const text = random('string'); + const result = createDivWithText(text); + + expect(result).toBeInstanceOf(Element); + expect(result.tagName).toBe('DIV'); + }); + + it('должна добавлять текст в элемент', () => { + const text = random('string'); + const result = createDivWithText(text); + + expect(result.textContent).toBe(text); + }); + }); + + describe('prepend', () => { + it('должна добавлять элемент в начало', () => { + const where = document.createElement('div'); + const what = document.createElement('p'); + const whereText = random('string'); + const whatText = random('string'); + + where.innerHTML = `, ${whereText}!`; + what.textContent = whatText; + + prepend(what, where); + + expect(where.firstChild).toBe(what); + expect(where.innerHTML).toBe(`

${whatText}

, ${whereText}!`); + }); + }); + + describe('findAllPSiblings', () => { + it('должна возвращать массив с элементами, соседями которых являются P', () => { + const where = document.createElement('div'); + + where.innerHTML = '

'; + const result = findAllPSiblings(where); + + expect(Array.isArray(result)); + expect(result).toEqual([where.children[0], where.children[3]]); + }); + }); + + describe('findError', () => { + it('должна возвращать массив из текстового содержимого элементов', () => { + const where = document.createElement('div'); + const text1 = random('string'); + const text2 = random('string'); + + where.innerHTML = `
${text1}
,
${text2}
!!!`; + const result = findError(where); + + expect(Array.isArray(result)); + expect(result).toEqual([text1, text2]); + }); + }); + + describe('deleteTextNodes', () => { + it('должна удалить все текстовые узлы', () => { + const where = document.createElement('div'); + + where.innerHTML = `
${random('string')}

${random('string')}`; + deleteTextNodes(where); + + expect(where.innerHTML).toBe('

'); + }); + }); + + describe('collectDOMStat', () => { + it('должна вернуть статистику по переданному дереву', () => { + const where = document.createElement('div'); + const class1 = `class-${random('number')}`; + const class2 = `class-${random('number')}-${random('number')}`; + const text1 = random('string'); + const text2 = random('string'); + const stat = { + tags: { P: 1, B: 2 }, + classes: { [class1]: 2, [class2]: 1 }, + texts: 3, + }; + + where.innerHTML = `

${text1} ${text2}

`; + const result = collectDOMStat(where); + + expect(result).toEqual(stat); + }); + }); +});