diff --git a/src/Plugin/Block/MenuBlock.php b/src/Plugin/Block/MenuBlock.php index 052a9dc..11c039f 100644 --- a/src/Plugin/Block/MenuBlock.php +++ b/src/Plugin/Block/MenuBlock.php @@ -68,21 +68,25 @@ class MenuBlock extends SystemMenuBlock { $form['advanced']['follow'] = [ '#type' => 'checkbox', - '#title' => "" . $this->t('Follow active trail') . "", + '#title' => $this->t('Make the initial visibility level follow the active menu item.'), '#default_value' => $config['follow'], - '#description' => $this->t('Follow current active trail.'), + '#description' => $this->t('If the active menu item is deeper than the initial visibility level set above, the initial visibility level will be relative to the active menu item. Otherwise, the initial visibility level of the tree will remain fixed.'), ]; $form['advanced']['follow_parent'] = [ '#type' => 'radios', - '#title' => "" . $this->t('Use parent item(s) for active trail') . "", + '#title' => $this->t('Initial visibility level will be'), + '#description' => $this->t('When following the active menu item, select whether the initial visibility level should be set to the active menu item, or its children.'), '#default_value' => $config['follow_parent'], - '#description' => $this->t('Instead of using the menu item itself as root item, use its parents (only applicable if "Follow active trail" is checked.'), - '#options' => array( - 1 => $this->t('Follow one parent'), - 0 => $this->t('Do not follow parents'), - -1 => $this->t('Follow all parents (excluding the root)') - ), + '#options' => [ + 'active' => t('Active menu item'), + 'child' => t('Children of active menu item'), + ], + '#states' => [ + 'visible' => [ + ':input[name="settings[follow]"]' => ['checked' => TRUE], + ], + ], ]; $form['style']['suggestion'] = [ @@ -141,34 +145,21 @@ class MenuBlock extends SystemMenuBlock { // Adjust the menu tree parameters based on the block's configuration. $level = $this->configuration['level']; - $original_level = $this->configuration['level']; $depth = $this->configuration['depth']; $expand = $this->configuration['expand']; $parent = $this->configuration['parent']; $follow = $this->configuration['follow']; $follow_parent = $this->configuration['follow_parent']; + $following = FALSE; - $max_depth = $level + $depth - 1; $parameters->setMinDepth($level); - $min_depth = $level; - - if ($follow) { - $level += count($parameters->activeTrail) - 1; - end($parameters->activeTrail); - $root_item = current($parameters->activeTrail); - if (empty($root_item) && count($parameters->activeTrail) > 1) { - $root_item = prev($parameters->activeTrail); - $level--; - } - if ($follow_parent == '1' && (($level - 1) >= $min_depth)) { - $root_item = prev($parameters->activeTrail); - $level--; - } - while ($follow_parent == '-1' && (($level - 1) >= $min_depth) && $level > 2) { - $root_item = prev($parameters->activeTrail); - $level--; - } - $parameters->setRoot($root_item); + + // If we're following the active trail and the active trail is deeper than + // the initial starting level, we update the level to match the active menu + // item's level in the menu. + if ($follow && count($parameters->activeTrail) > $level) { + $level = count($parameters->activeTrail); + $following = TRUE; } // When the depth is configured to zero, there is no depth limit. When depth @@ -176,30 +167,25 @@ class MenuBlock extends SystemMenuBlock { // Hence this is a relative depth that we must convert to an actual // (absolute) depth, that may never exceed the maximum depth. if ($depth > 0) { - $parameters->setMaxDepth(min($max_depth, $this->menuTree->maxDepth())); - } - - // If the active trail contains less (non-empty) items then the original - // level, hide the block. - if ($follow_parent == '-1' && count(array_filter($parameters->activeTrail)) < $original_level) { - return array(); + $parameters->setMaxDepth(min($level + $depth - 1, $this->menuTree->maxDepth())); } - // For menu blocks with start level greater than 1, only show menu items - // from the current active trail. Adjust the root according to the current - // position in the menu in order to determine if we can show the subtree. - // If we're using a fixed parent item, we'll skip this step. + // If we're currently following an active menu item, or for menu blocks with + // start level greater than 1, only show menu items from the current active + // trail. Adjust the root according to the current position in the menu in + // order to determine if we can show the subtree. If we're not following an + // active trail and using a fixed parent item, we'll skip this step. $fixed_parent_menu_link_id = str_replace($menu_name . ':', '', $parent); - if ($level > 1 && !$fixed_parent_menu_link_id) { + if ($following || ($level > 1 && !$fixed_parent_menu_link_id)) { if (count($parameters->activeTrail) >= $level) { // Active trail array is child-first. Reverse it, and pull the new menu // root based on the parent of the configured start level. $menu_trail_ids = array_reverse(array_values($parameters->activeTrail)); - $menu_root = $menu_trail_ids[$level - 1]; + $offset = ($following && $follow_parent == 'active') ? 2 : 1; + $menu_root = $menu_trail_ids[$level - $offset]; $parameters->setRoot($menu_root)->setMinDepth(1); if ($depth > 0) { - $max_depth = min($level - 1 + $depth - 1, $this->menuTree->maxDepth()); - $parameters->setMaxDepth($max_depth); + $parameters->setMaxDepth(min($depth, $this->menuTree->maxDepth())); } } else { @@ -211,26 +197,39 @@ class MenuBlock extends SystemMenuBlock { if ($expand) { $parameters->expandedParents = []; } + // When a fixed parent item is set, root the menu tree at the given ID. if ($fixed_parent_menu_link_id) { - $parameters->setRoot($fixed_parent_menu_link_id); - - // If the starting level is 1, we always want the child links to appear, - // but the requested tree may be empty if the tree does not contain the - // active trail. - if ($level === 1 || $level === '1') { - // Check if the tree contains links. - $tree = $this->menuTree->load($menu_name, $parameters); - if (empty($tree)) { + // Clone the parameters so we can fall back to using them if we're + // following the active menu item and the current page is part of the + // active menu trail. + $fixed_parameters = clone $parameters; + $fixed_parameters->setRoot($fixed_parent_menu_link_id); + $tree = $this->menuTree->load($menu_name, $fixed_parameters); + + // Check if the tree contains links. + if (empty($tree)) { + // If the starting level is 1, we always want the child links to appear, + // but the requested tree may be empty if the tree does not contain the + // active trail. We're accessing the configuration directly since the + // $level variable may have changed by this point. + if ($this->configuration['level'] === 1 || $this->configuration['level'] === '1') { // Change the request to expand all children and limit the depth to // the immediate children of the root. - $parameters->expandedParents = []; - $parameters->setMinDepth(1); - $parameters->setMaxDepth(1); + $fixed_parameters->expandedParents = []; + $fixed_parameters->setMinDepth(1); + $fixed_parameters->setMaxDepth(1); // Re-load the tree. - $tree = $this->menuTree->load($menu_name, $parameters); + $tree = $this->menuTree->load($menu_name, $fixed_parameters); } } + elseif ($following) { + // If we're following the active menu item, and the tree isn't empty + // (which indicates we're currently in the active trail), we unset + // the tree we made and just let the active menu parameters from before + // do their thing. + unset($tree); + } } // Load the tree if we haven't already. @@ -276,7 +275,7 @@ class MenuBlock extends SystemMenuBlock { public function defaultConfiguration() { return [ 'follow' => 0, - 'follow_parent' => 0, + 'follow_parent' => 'child', 'level' => 1, 'depth' => 0, 'expand' => 0,