Skip to content

Commit 8bcfe4f

Browse files
authored
ENGCOM-4623: Make sure 'last' class is set on top menu #22071
2 parents db9eaf1 + 32c6daf commit 8bcfe4f

File tree

1 file changed

+100
-49
lines changed

1 file changed

+100
-49
lines changed

app/code/Magento/Theme/Block/Html/Topmenu.php

Lines changed: 100 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
*/
66
namespace Magento\Theme\Block\Html;
77

8+
use Magento\Backend\Model\Menu;
89
use Magento\Framework\Data\Tree\Node;
10+
use Magento\Framework\Data\Tree\Node\Collection;
911
use Magento\Framework\Data\Tree\NodeFactory;
1012
use Magento\Framework\Data\TreeFactory;
13+
use Magento\Framework\DataObject;
1114
use Magento\Framework\DataObject\IdentityInterface;
1215
use Magento\Framework\View\Element\Template;
1316

@@ -29,7 +32,7 @@ class Topmenu extends Template implements IdentityInterface
2932
/**
3033
* Top menu data tree
3134
*
32-
* @var \Magento\Framework\Data\Tree\Node
35+
* @var Node
3336
*/
3437
protected $_menu;
3538

@@ -89,28 +92,35 @@ public function getHtml($outermostClass = '', $childrenWrapClass = '', $limit =
8992
$this->getMenu()->setOutermostClass($outermostClass);
9093
$this->getMenu()->setChildrenWrapClass($childrenWrapClass);
9194

92-
$html = $this->_getHtml($this->getMenu(), $childrenWrapClass, $limit);
95+
$transportObject = new DataObject(
96+
[
97+
'html' => $this->_getHtml(
98+
$this->getMenu(),
99+
$childrenWrapClass,
100+
$limit
101+
)
102+
]
103+
);
93104

94-
$transportObject = new \Magento\Framework\DataObject(['html' => $html]);
95105
$this->_eventManager->dispatch(
96106
'page_block_html_topmenu_gethtml_after',
97107
['menu' => $this->getMenu(), 'transportObject' => $transportObject]
98108
);
99-
$html = $transportObject->getHtml();
100-
return $html;
109+
110+
return $transportObject->getHtml();
101111
}
102112

103113
/**
104114
* Count All Subnavigation Items
105115
*
106-
* @param \Magento\Backend\Model\Menu $items
116+
* @param Menu $items
107117
* @return int
108118
*/
109119
protected function _countItems($items)
110120
{
111121
$total = $items->count();
112122
foreach ($items as $item) {
113-
/** @var $item \Magento\Backend\Model\Menu\Item */
123+
/** @var $item Menu\Item */
114124
if ($item->hasChildren()) {
115125
$total += $this->_countItems($item->getChildren());
116126
}
@@ -121,7 +131,7 @@ protected function _countItems($items)
121131
/**
122132
* Building Array with Column Brake Stops
123133
*
124-
* @param \Magento\Backend\Model\Menu $items
134+
* @param Menu $items
125135
* @param int $limit
126136
* @return array|void
127137
*
@@ -164,7 +174,7 @@ protected function _columnBrake($items, $limit)
164174
/**
165175
* Add sub menu HTML code for current menu item
166176
*
167-
* @param \Magento\Framework\Data\Tree\Node $child
177+
* @param Node $child
168178
* @param string $childLevel
169179
* @param string $childrenWrapClass
170180
* @param int $limit
@@ -192,59 +202,46 @@ protected function _addSubMenu($child, $childLevel, $childrenWrapClass, $limit)
192202
/**
193203
* Recursively generates top menu html from data that is specified in $menuTree
194204
*
195-
* @param \Magento\Framework\Data\Tree\Node $menuTree
205+
* @param Node $menuTree
196206
* @param string $childrenWrapClass
197207
* @param int $limit
198208
* @param array $colBrakes
199209
* @return string
200-
*
201-
* @SuppressWarnings(PHPMD.CyclomaticComplexity)
202-
* @SuppressWarnings(PHPMD.NPathComplexity)
203210
*/
204211
protected function _getHtml(
205-
\Magento\Framework\Data\Tree\Node $menuTree,
212+
Node $menuTree,
206213
$childrenWrapClass,
207214
$limit,
208215
array $colBrakes = []
209216
) {
210217
$html = '';
211218

212219
$children = $menuTree->getChildren();
213-
$parentLevel = $menuTree->getLevel();
214-
$childLevel = $parentLevel === null ? 0 : $parentLevel + 1;
220+
$childLevel = $this->getChildLevel($menuTree->getLevel());
221+
$this->removeChildrenWithoutActiveParent($children, $childLevel);
215222

216223
$counter = 1;
217-
$itemPosition = 1;
218224
$childrenCount = $children->count();
219225

220226
$parentPositionClass = $menuTree->getPositionClass();
221227
$itemPositionClassPrefix = $parentPositionClass ? $parentPositionClass . '-' : 'nav-';
222228

223-
/** @var \Magento\Framework\Data\Tree\Node $child */
229+
/** @var Node $child */
224230
foreach ($children as $child) {
225-
if ($childLevel === 0 && $child->getData('is_parent_active') === false) {
226-
continue;
227-
}
228231
$child->setLevel($childLevel);
229-
$child->setIsFirst($counter == 1);
230-
$child->setIsLast($counter == $childrenCount);
232+
$child->setIsFirst($counter === 1);
233+
$child->setIsLast($counter === $childrenCount);
231234
$child->setPositionClass($itemPositionClassPrefix . $counter);
232235

233236
$outermostClassCode = '';
234237
$outermostClass = $menuTree->getOutermostClass();
235238

236-
if ($childLevel == 0 && $outermostClass) {
239+
if ($childLevel === 0 && $outermostClass) {
237240
$outermostClassCode = ' class="' . $outermostClass . '" ';
238-
$currentClass = $child->getClass();
239-
240-
if (empty($currentClass)) {
241-
$child->setClass($outermostClass);
242-
} else {
243-
$child->setClass($currentClass . ' ' . $outermostClass);
244-
}
241+
$this->setCurrentClass($child, $outermostClass);
245242
}
246243

247-
if (is_array($colBrakes) && count($colBrakes) && $colBrakes[$counter]['colbrake']) {
244+
if ($this->shouldAddNewColumn($colBrakes, $counter)) {
248245
$html .= '</ul></li><li class="column"><ul>';
249246
}
250247

@@ -257,11 +254,10 @@ protected function _getHtml(
257254
$childrenWrapClass,
258255
$limit
259256
) . '</li>';
260-
$itemPosition++;
261257
$counter++;
262258
}
263259

264-
if (is_array($colBrakes) && count($colBrakes) && $limit) {
260+
if (is_array($colBrakes) && !empty($colBrakes) && $limit) {
265261
$html = '<li class="column"><ul>' . $html . '</ul></li>';
266262
}
267263

@@ -271,14 +267,13 @@ protected function _getHtml(
271267
/**
272268
* Generates string with all attributes that should be present in menu item element
273269
*
274-
* @param \Magento\Framework\Data\Tree\Node $item
270+
* @param Node $item
275271
* @return string
276272
*/
277-
protected function _getRenderedMenuItemAttributes(\Magento\Framework\Data\Tree\Node $item)
273+
protected function _getRenderedMenuItemAttributes(Node $item)
278274
{
279275
$html = '';
280-
$attributes = $this->_getMenuItemAttributes($item);
281-
foreach ($attributes as $attributeName => $attributeValue) {
276+
foreach ($this->_getMenuItemAttributes($item) as $attributeName => $attributeValue) {
282277
$html .= ' ' . $attributeName . '="' . str_replace('"', '\"', $attributeValue) . '"';
283278
}
284279
return $html;
@@ -287,27 +282,26 @@ protected function _getRenderedMenuItemAttributes(\Magento\Framework\Data\Tree\N
287282
/**
288283
* Returns array of menu item's attributes
289284
*
290-
* @param \Magento\Framework\Data\Tree\Node $item
285+
* @param Node $item
291286
* @return array
292287
*/
293-
protected function _getMenuItemAttributes(\Magento\Framework\Data\Tree\Node $item)
288+
protected function _getMenuItemAttributes(Node $item)
294289
{
295-
$menuItemClasses = $this->_getMenuItemClasses($item);
296-
return ['class' => implode(' ', $menuItemClasses)];
290+
return ['class' => implode(' ', $this->_getMenuItemClasses($item))];
297291
}
298292

299293
/**
300294
* Returns array of menu item's classes
301295
*
302-
* @param \Magento\Framework\Data\Tree\Node $item
296+
* @param Node $item
303297
* @return array
304298
*/
305-
protected function _getMenuItemClasses(\Magento\Framework\Data\Tree\Node $item)
299+
protected function _getMenuItemClasses(Node $item)
306300
{
307-
$classes = [];
308-
309-
$classes[] = 'level' . $item->getLevel();
310-
$classes[] = $item->getPositionClass();
301+
$classes = [
302+
'level' . $item->getLevel(),
303+
$item->getPositionClass(),
304+
];
311305

312306
if ($item->getIsCategory()) {
313307
$classes[] = 'category-item';
@@ -375,7 +369,7 @@ protected function getCacheTags()
375369
/**
376370
* Get menu object.
377371
*
378-
* Creates \Magento\Framework\Data\Tree\Node root node object.
372+
* Creates Tree root node object.
379373
* The creation logic was moved from class constructor into separate method.
380374
*
381375
* @return Node
@@ -394,4 +388,61 @@ public function getMenu()
394388
}
395389
return $this->_menu;
396390
}
391+
392+
/**
393+
* Remove children from collection when the parent is not active
394+
*
395+
* @param Collection $children
396+
* @param int $childLevel
397+
* @return void
398+
*/
399+
private function removeChildrenWithoutActiveParent(Collection $children, int $childLevel): void
400+
{
401+
/** @var Node $child */
402+
foreach ($children as $child) {
403+
if ($childLevel === 0 && $child->getData('is_parent_active') === false) {
404+
$children->delete($child);
405+
}
406+
}
407+
}
408+
409+
/**
410+
* Retrieve child level based on parent level
411+
*
412+
* @param int $parentLevel
413+
*
414+
* @return int
415+
*/
416+
private function getChildLevel($parentLevel): int
417+
{
418+
return $parentLevel === null ? 0 : $parentLevel + 1;
419+
}
420+
421+
/**
422+
* Check if new column should be added.
423+
*
424+
* @param array $colBrakes
425+
* @param int $counter
426+
* @return bool
427+
*/
428+
private function shouldAddNewColumn(array $colBrakes, int $counter): bool
429+
{
430+
return count($colBrakes) && $colBrakes[$counter]['colbrake'];
431+
}
432+
433+
/**
434+
* Set current class.
435+
*
436+
* @param Node $child
437+
* @param string $outermostClass
438+
*/
439+
private function setCurrentClass(Node $child, string $outermostClass): void
440+
{
441+
$currentClass = $child->getClass();
442+
if (empty($currentClass)) {
443+
$child->setClass($outermostClass);
444+
} else {
445+
$child->setClass($currentClass . ' ' . $outermostClass);
446+
}
447+
}
397448
}

0 commit comments

Comments
 (0)