# Схема решения Дерево устроено как вложенный список. Клики на все элементы можно поймать, повесив единый обработчик `onclick` на внешний `UL`. Как поймать клик на заголовке? Элемент `LI` является блочным, поэтому нельзя понять, был ли клик на *тексте*, или справа от него. Например, ниже -- участок дерева с выделенными рамкой узлами. Кликните справа от любого заголовка. Видите, клик ловится? А лучше бы такие клики (не на тексте) игнорировать. ```html ``` В примере выше видно, что проблема в верстке, в том что `LI` занимает всю ширину. Можно кликнуть справа от текста, это все еще `LI`. Один из способов это поправить -- обернуть заголовки в дополнительный элемент `SPAN`, и обрабатывать только клики внутри `SPAN'ов`, получать по `SPAN'у` его родителя `LI` и ставить ему класс открыт/закрыт. Напишите для этого JavaScript-код. # Оборачиваем заголовки в SPAN Следующий код ищет все `LI` и оборачивает текстовые узлы в `SPAN`. ```js var treeUl = document.getElementsByTagName('ul')[0]; var treeLis = treeUl.getElementsByTagName('li'); for (var i = 0; i < treeLis.length; i++) { var li = treeLis[i]; var span = document.createElement('span'); li.insertBefore(span, li.firstChild); // добавить пустой SPAN span.appendChild(span.nextSibling); // переместить в него заголовок } ``` Теперь можно отслеживать клики *на заголовках*. Так выглядит дерево с обёрнутыми в `SPAN` заголовками и делегированием: ```html ``` Так как `SPAN` -- инлайновый элемент, он всегда такого же размера как текст. Да здравствует `SPAN`! В реальной жизни дерево, скорее всего, будет сразу со `SPAN`: если HTML-код дерева генерируется на сервере, то это несложно, если дерево генерируется в JavaScript -- тем более просто. # Итоговое решение Для делегирования нужно по клику понять, на каком узле он произошел. В нашем случае у `SPAN` нет детей-элементов, поэтому не нужно подниматься вверх по цепочке родителей. Достаточно просто проверить `event.target.tagName == 'SPAN'`, чтобы понять, где был клик, и спрятать потомков. ```js var tree = document.getElementsByTagName('ul')[0]; tree.onclick = function(event) { var target = event.target; if (target.tagName != 'SPAN') { return; // клик был не на заголовке } var li = target.parentNode; // получить родительский LI // получить UL с потомками -- это первый UL внутри LI var childrenContainer = li.getElementsByTagName('ul')[0]; if (!childrenContainer) return; // потомков нет -- ничего не надо делать // спрятать/показать (можно и через CSS-класс) childrenContainer.hidden = !childrenContainer.hidden; } ``` Выделение узлов жирным при наведении делается при помощи CSS-селектора `:hover`.