Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions dxpr_theme.libraries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -214,3 +214,9 @@ enhanced-dropdowns:
vendor/enhanced-dropdowns/dist/css/main.min.css: { minified: true }
dependencies:
- core/drupal

active-trail:
js:
js/dist/dxpr-theme-active-trail.js: {}
dependencies:
- core/drupal
24 changes: 13 additions & 11 deletions dxpr_theme.theme
Original file line number Diff line number Diff line change
Expand Up @@ -276,26 +276,22 @@ function dxpr_theme_preprocess_page(&$variables) {
/**
* Implements hook_preprocess_menu().
*
* Workaround for Drupal core regression where Views-generated menu links don't
* receive proper active trail detection. Compares menu item URLs against the
* current page path to set active states and propagates to parent items.
* Attaches client-side active trail detection for Views-generated menu links
* that core does not mark as active (core issue #3359511). This removes the
* extra url.path cache context that the previous server-side workaround added;
* the core route.menu_active_trails cache context remains on menu blocks.
*
* @see https://www.drupal.org/project/dxpr_theme/issues/3553914
* @see https://www.drupal.org/project/drupal/issues/3359511
*
* @todo Remove when core issue #3359511 is resolved.
*/
function dxpr_theme_preprocess_menu(&$variables) {
if (empty($variables['items'])) {
return;
}

$current_path = \Drupal::service('path.current')->getPath();
$is_front = \Drupal::service('path.matcher')->isFrontPage();
dxpr_theme_menu_set_active_trail($variables['items'], $current_path, $is_front);

// Ensure menu is cached per URL to prevent wrong active states.
$variables['#cache']['contexts'][] = 'url.path';
// Attach client-side active trail detection for edge cases (e.g.
// Views-generated menu links) not covered by core's built-in active trail.
$variables['#attached']['library'][] = 'dxpr_theme/active-trail';
}

/**
Expand All @@ -310,6 +306,12 @@ function dxpr_theme_preprocess_menu(&$variables) {
*
* @return bool
* TRUE if any item in this level or below is active.
*
* @deprecated in dxpr_theme:8.2.0 and is removed from dxpr_theme:9.0.0.
* Active trail detection is now handled client-side via the active-trail
* library. This function is retained for backward compatibility but is no
* longer called by dxpr_theme_preprocess_menu().
* @see https://www.drupal.org/project/dxpr_theme/issues/3509999
*/
function dxpr_theme_menu_set_active_trail(array &$items, $current_path, $is_front) {
$has_active = FALSE;
Expand Down
46 changes: 46 additions & 0 deletions js/dist/dxpr-theme-active-trail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* @file
* Client-side active trail detection for menu links.
*
* Supplements core's built-in active trail with client-side detection so that
* the server-rendered menu does not need a url.path cache context. This covers
* edge cases such as Views-generated menu links that core does not mark as
* active (see https://www.drupal.org/project/drupal/issues/3359511).
*/

(function (Drupal) {
Drupal.behaviors.dxprThemeActiveTrail = {
attach(context) {
if (context !== document) {
return;
}
const currentPath = window.location.pathname;
const currentOrigin = window.location.origin;
const menuLinks = document.querySelectorAll(".menu--main a[href]");
menuLinks.forEach((link) => {
const rawHref = link.getAttribute("href");
if (!rawHref || rawHref.startsWith("#")) {
return;
}
const linkUrl = new URL(link.href, currentOrigin);
if (linkUrl.origin !== currentOrigin) {
return;
}
if (linkUrl.pathname === currentPath) {
link.classList.add("is-active");
let li = link.closest("li");
while (li) {
li.classList.add("menu-item--active-trail");
li.classList.add("active");
const parentUl = li.parentElement;
if (parentUl) {
li = parentUl.closest("li");
} else {
break;
}
}
}
});
},
};
})(Drupal);
Loading