diff --git a/src/Plugin/Block/MenuBlock.php b/src/Plugin/Block/MenuBlock.php
index fab522a..5d94c95 100644
--- a/src/Plugin/Block/MenuBlock.php
+++ b/src/Plugin/Block/MenuBlock.php
@@ -41,17 +41,78 @@ class MenuBlock extends SystemMenuBlock {
'#description' => $this->t('All menu links that have children will "Show as expanded".'),
];
+ $form['advanced']['expand_only_active_trails'] = [
+ '#type' => 'checkbox',
+ '#title' => $this->t('Expand only active tree'),
+ '#default_value' => $config['expand_only_active_trails'],
+ '#description' => $this->t('All menu links that are in active trails will "Show as expanded".'),
+ '#states' => [
+ 'visible' => [
+ ':input[name="settings[expand]"]' => ['checked' => TRUE],
+ ]
+ ]
+ ];
+
$menu_name = $this->getDerivativeId();
$menus = Menu::loadMultiple(array($menu_name));
$menus[$menu_name] = $menus[$menu_name]->label();
/** @var \Drupal\Core\Menu\MenuParentFormSelectorInterface $menu_parent_selector */
$menu_parent_selector = \Drupal::service('menu.parent_form_selector');
- $form['advanced']['parent'] = $menu_parent_selector->parentSelectElement($config['parent'], '', $menus);
+ if (strpos($config['parent'], 'active_trail') === FALSE) {
+ $form['advanced']['parent'] = $menu_parent_selector->parentSelectElement($config['parent'], '', $menus);
+ }
+ else {
+ $form['advanced']['parent'] = [
+ '#type' => 'select',
+ '#options' => $menu_parent_selector->getParentSelectOptions('', $menus),
+ '#default_value' => $config['parent'],
+ ];
+ }
+ $form['advanced']['parent']['#options'] += [
+ $menu_name . ':active_trail' => $this->t('')->render(),
+ $menu_name . ':active_trail_parent' => $this->t('')->render(),
+ $menu_name . ':active_trail_custom' => $this->t('')->render(),
+ ];
$form['advanced']['parent'] += [
'#title' => $this->t('Fixed parent item'),
'#description' => $this->t('Alter the options in “Menu levels” to be relative to the fixed parent item. The block will only contain children of the selected menu link.'),
+ '#attributes' => [
+ 'class' => ['active-trail'],
+ ],
+ ];
+
+ $custom_level_options = function() {
+ $options = range(0,9);
+ return array_combine($options, $options);
+ };
+
+ $form['advanced']['custom_level'] = [
+ '#type' => 'select',
+ '#title' => $this->t('Set custom depth, set dynamically relative to the active trail.'),
+ '#default_value' => $config['custom_level'],
+ '#options' => $custom_level_options(),
+ '#states' => [
+ 'visible' => [
+ '.active-trail' => ['value' => $menu_name . ':active_trail_custom'],
+ ],
+ ],
+ ];
+
+ $form['advanced']['hide_children'] = [
+ '#type' => 'checkbox',
+ '#title' => $this->t('Hide children of parent in active trail?'),
+ '#default_value' => $config['hide_children'],
+ '#states' => [
+ 'visible' => [
+ '.active-trail' => [
+ ['value' => $menu_name . ':active_trail'],
+ ['value' => $menu_name . ':active_trail_parent'],
+ ['value' => $menu_name . ':active_trail_custom'],
+ ],
+ ],
+ ],
];
$form['style'] = [
@@ -99,8 +160,11 @@ class MenuBlock extends SystemMenuBlock {
*/
public function blockSubmit($form, FormStateInterface $form_state) {
$this->configuration['level'] = $form_state->getValue('level');
+ $this->configuration['custom_level'] = $form_state->getValue('custom_level');
+ $this->configuration['hide_children'] = $form_state->getValue('hide_children');
$this->configuration['depth'] = $form_state->getValue('depth');
$this->configuration['expand'] = $form_state->getValue('expand');
+ $this->configuration['expand_only_active_trails'] = $form_state->getValue('expand_only_active_trails');
$this->configuration['parent'] = $form_state->getValue('parent');
$this->configuration['suggestion'] = $form_state->getValue('suggestion');
}
@@ -114,11 +178,21 @@ class MenuBlock extends SystemMenuBlock {
// Adjust the menu tree parameters based on the block's configuration.
$level = $this->configuration['level'];
+ $custom_level = $this->configuration['custom_level'];
$depth = $this->configuration['depth'];
$expand = $this->configuration['expand'];
+ $expand_only_active_trails = $this->configuration['expand_only_active_trails'];
$parent = $this->configuration['parent'];
+ $hide_children = $this->configuration['hide_children'];
$suggestion = $this->configuration['suggestion'];
+ $trail_ids = $this->menuActiveTrail->getActiveTrailIds($menu_name);
+ $trail_ids = array_reverse(array_filter($trail_ids));
+
+ if ($parent == $menu_name . ':' . 'active_trail_custom') {
+ $level = $this->setActiveTrailLevel($level, $custom_level, $trail_ids);
+ }
+
$parameters->setMinDepth($level);
// When the depth is configured to zero, there is no depth limit. When depth
// is non-zero, it indicates the number of levels that must be displayed.
@@ -128,29 +202,47 @@ class MenuBlock extends SystemMenuBlock {
$parameters->setMaxDepth(min($level + $depth - 1, $this->menuTree->maxDepth()));
}
// If expandedParents is empty, the whole menu tree is built.
- if ($expand) {
+ if ($expand && !$expand_only_active_trails) {
$parameters->expandedParents = array();
}
// When a fixed parent item is set, root the menu tree at the given ID.
if ($menuLinkID = str_replace($menu_name . ':', '', $parent)) {
- $parameters->setRoot($menuLinkID);
-
- // 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(NULL, $parameters);
- if (empty($tree)) {
- // Change the request to expand all children and limit the depth to
- // the immediate children of the root.
- $parameters->expandedParents = array();
- $parameters->setMinDepth(1);
- $parameters->setMaxDepth(1);
- // Re-load the tree.
+ if (strpos($menuLinkID, 'custom') == FALSE) {
+ // Active trail or Active trail parent option.
+ if (strpos($menuLinkID, 'active_trail') !== FALSE) {
+ // $trail_ids = $this->menuActiveTrail->getActiveTrailIds($menu_name);
+ // $trail_ids = array_reverse(array_filter($trail_ids));
+ if ($menuLinkID == 'active_trail') {
+ $menuLinkID = end($trail_ids);
+ }
+ // Active trail parent.
+ else {
+ array_pop($trail_ids);
+ $menuLinkID = end($trail_ids);
+ }
+ }
+ if ($menuLinkID) {
+ $parameters->setRoot($menuLinkID);
+ }
+
+ // 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(NULL, $parameters);
+ if (empty($tree)) {
+ // Change the request to expand all children and limit the depth to
+ // the immediate children of the root.
+ $parameters->expandedParents = array();
+ $parameters->setMinDepth(1);
+ $parameters->setMaxDepth(1);
+ // Re-load the tree.
+ $tree = $this->menuTree->load(NULL, $parameters);
+ }
}
}
+ // end custom
}
// Load the tree if we haven't already.
@@ -161,7 +253,13 @@ class MenuBlock extends SystemMenuBlock {
array('callable' => 'menu.default_tree_manipulators:checkAccess'),
array('callable' => 'menu.default_tree_manipulators:generateIndexAndSort'),
);
+
$tree = $this->menuTree->transform($tree, $manipulators);
+ // Hide parent children if it is set in config.
+ if ($hide_children) {
+ $tree = $this->hideParentChildren($tree);
+ }
+
$build = $this->menuTree->build($tree);
if (!empty($build['#theme'])) {
@@ -176,13 +274,54 @@ class MenuBlock extends SystemMenuBlock {
}
/**
+ * Set the menu level relative to the active trail.
+ */
+ public function setActiveTrailLevel($level, $custom_level, $trail_ids) {
+ $dynamic_level = count($trail_ids) - $custom_level;
+ if ($dynamic_level >= 1) {
+ $level = $dynamic_level;
+ }
+
+ return $level;
+ }
+
+ /**
+ * Hide the children of the active parent.
+ */
+ public function hideParentChildren($tree) {
+ $not_active_items = [];
+ $unset = FALSE;
+ if (count($tree)) {
+ foreach ($tree as $id => $branch) {
+ if (!$branch->inActiveTrail) {
+ $not_active_items[$id] = $id;
+ }
+ if ($branch->inActiveTrail && $branch->hasChildren) {
+ $unset = TRUE;
+ }
+ }
+ }
+
+ if ($unset) {
+ foreach ($not_active_items as $not_active_item) {
+ unset($tree[$not_active_item]);
+ }
+ }
+
+ return $tree;
+ }
+
+ /**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [
'level' => 1,
+ 'custom_level' => 1,
+ 'hide_children' => 0,
'depth' => 0,
'expand' => 0,
+ 'expand_only_active_trails' => 0,
'parent' => $this->getDerivativeId() . ':',
'suggestion' => strtr($this->getDerivativeId(), '-', '_'),
];