diff --git a/assets/js/misc/active-link-trail.js b/assets/js/misc/active-link-trail.js new file mode 100644 index 0000000000000000000000000000000000000000..1feb460a9e17315ad1af4ef234201116b7104d19 --- /dev/null +++ b/assets/js/misc/active-link-trail.js @@ -0,0 +1,62 @@ +/** + * @file + * Attaches behaviors for Drupal's active trail link marking. + */ + +((Drupal, drupalSettings) => { + const activeClass = 'active'; + + /** + * Append active class. + * + * The link is only active if it has data-drupal-active-trail=true. + * + * Does not discriminate based on element type, so allows you to set the + * active class on any element: a, li… + * + * @type {Drupal~behavior} + */ + Drupal.behaviors.ui_suite_bootstrap_activeTrailLinks = { + attach(context) { + // Start by finding all potentially active links. + const { path } = drupalSettings; + const queryString = JSON.stringify(path.currentQuery); + const querySelector = queryString + ? `[data-drupal-link-query="${CSS.escape(queryString)}"]` + : ':not([data-drupal-link-query])'; + const originalSelectors = [`[data-drupal-active-trail=true]`]; + let selectors; + + // Add language filtering. + selectors = [].concat( + // Links without any hreflang attributes (most of them). + originalSelectors.map((selector) => `${selector}:not([hreflang])`), + // Links with hreflang equals to the current language. + originalSelectors.map( + (selector) => `${selector}[hreflang="${path.currentLanguage}"]`, + ), + ); + + // Add query string selector for pagers, exposed filters. + selectors = selectors.map((current) => current + querySelector); + + // Query the DOM. + const activeLinks = context.querySelectorAll(selectors.join(',')); + const il = activeLinks.length; + for (let i = 0; i < il; i++) { + activeLinks[i].classList.add(activeClass); + } + }, + detach(context, settings, trigger) { + if (trigger === 'unload') { + const activeLinks = context.querySelectorAll( + `[data-drupal-active-trail=true]`, + ); + const il = activeLinks.length; + for (let i = 0; i < il; i++) { + activeLinks[i].classList.remove(activeClass); + } + } + }, + }; +})(Drupal, drupalSettings); diff --git a/assets/js/misc/active-link.js b/assets/js/misc/active-link.js index ff094246c18e86e83a1ffa2de7d87be4be46b00b..b40b7739c4d3110705c0759a10ff3c99b66c1991 100644 --- a/assets/js/misc/active-link.js +++ b/assets/js/misc/active-link.js @@ -25,12 +25,11 @@ // Start by finding all potentially active links. const { path } = drupalSettings; const queryString = JSON.stringify(path.currentQuery); - const querySelector = path.currentQuery - ? `[data-drupal-link-query='${queryString}']` + const querySelector = queryString + ? `[data-drupal-link-query="${CSS.escape(queryString)}"]` : ':not([data-drupal-link-query])'; const originalSelectors = [ - `[data-drupal-link-system-path="${path.currentPath}"]`, - `[data-drupal-active-trail=true]`, + `[data-drupal-link-system-path="${CSS.escape(path.currentPath)}"]`, ]; let selectors; @@ -58,17 +57,18 @@ const il = activeLinks.length; for (let i = 0; i < il; i++) { activeLinks[i].classList.add(activeClass); + activeLinks[i].setAttribute('aria-current', 'page'); } }, detach(context, settings, trigger) { if (trigger === 'unload') { const activeLinks = context.querySelectorAll( `[data-drupal-link-system-path].${activeClass}`, - `[data-drupal-active-trail=true]`, ); const il = activeLinks.length; for (let i = 0; i < il; i++) { activeLinks[i].classList.remove(activeClass); + activeLinks[i].removeAttribute('aria-current'); } } }, diff --git a/ui_suite_bootstrap.info.yml b/ui_suite_bootstrap.info.yml index 1da0622b0f17c28ce36fa186f24b1d4d04bcf2e3..45c9bb7f6e6afa34f77ee946e07afe2fc051dd66 100644 --- a/ui_suite_bootstrap.info.yml +++ b/ui_suite_bootstrap.info.yml @@ -101,6 +101,8 @@ libraries-override: css/icon.autocomplete.css: false libraries-extend: + core/drupal.active-link: + - ui_suite_bootstrap/drupal.active-link core/drupal.ajax: - ui_suite_bootstrap/drupal.ajax core/drupal.autocomplete: diff --git a/ui_suite_bootstrap.libraries.yml b/ui_suite_bootstrap.libraries.yml index a08104b2f53831e840f6b25910af1663d2c60bee..0b6bdce97a64bb0f663c624620994837865f931f 100644 --- a/ui_suite_bootstrap.libraries.yml +++ b/ui_suite_bootstrap.libraries.yml @@ -23,6 +23,13 @@ component_placeholder: theme: assets/css/component/placeholder.css: {} +drupal.active-link: + js: + assets/js/misc/active-link-trail.js: { } + dependencies: + - core/drupal + - core/drupalSettings + drupal.ajax: js: assets/js/misc/ajax.js: {}