prepareTree($tree, $parent, $selectedId); return $this->renderItems($tree, $attribs); } protected function prepareTree(&$tree, &$parent, $selectedId) { if ($parent) { $parent['opened'] = false; } foreach ($tree as &$item) { $item['selected'] = $item['id'] == $selectedId; if (!empty($item['sub'])) { $this->prepareTree($item['sub'], $item, $selectedId); } if (($item['id'] == $selectedId || Qs_Array::get($item, 'opened'))) { if ($parent) { $parent['opened'] = true; } $item['opened'] = true; } } return $this; } protected function renderItems($tree, $attribs, $level = 1) { $xhtml = ''; $index = 0; $count = count($tree); foreach ($tree as $item) { $xhtml .= $this->renderItem($item, $level, ++$index == $count); } return Html::renderContainer('ul', $xhtml, $attribs); } protected function renderItem($item, $level, $last) { $attribs = [ 'class' => [] ]; if (($isTop = (1 == $level))) { $attribs['class'][] = 'top-level'; } $xhtml = ''; $opened = Qs_Array::get($item, 'opened'); if (!empty($item['sub'])) { $branchClass = $opened ? 'collapsable' : 'expandable'; $attribs['class'][] = $branchClass; if ($last) { $attribs['class'][] = 'last' . ucfirst($branchClass); } $xhtml .= $this->renderHitarea($isTop, $opened, $last); } $xhtml .= $this->renderLink($item, $isTop); if (!empty($item['sub'])) { $ulAttribs = []; if (!$opened) { $ulAttribs['style'] = 'display:none'; } $xhtml .= $this->renderItems($item['sub'], $ulAttribs, $level + 1); } elseif ($last) { $attribs['class'][] = 'last'; } $attribs['class'] = implode(' ', $attribs['class']); return Html::renderContainer('li', $xhtml, $attribs); } protected function renderLink($item, $isTop) { $attribs = ['href' => $item['url'], 'class' => []]; if ($isTop) { $attribs['class'][] = 'top-level'; } if ($item['selected']) { $attribs['class'][] = 'selected'; } if (!empty($attribs['class'])) { $attribs['class'] = implode(' ', $attribs['class']); } else { unset($attribs['class']); } return Html::renderContainer('a', $item['title'], $attribs); } protected function renderHitarea($isTop, $opened, $last) { $class = ['hitarea']; if ($isTop) { $class[] = 'top-level-hitarea'; } $class[] = ($stateClass = ($opened ? 'collapsable' : 'expandable') . '-hitarea'); if ($last) { $class[] = 'last' . ucfirst($stateClass); } return Html::renderContainer('div', '', ['class' => implode(' ', $class)]); } }