diff -u b/core/includes/theme.inc b/core/includes/theme.inc --- b/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1641,6 +1641,8 @@ * http://www.w3.org/TR/WCAG-TECHS/H42.html for more information. */ function theme_links($variables) { + $language_url = language(Language::TYPE_URL); + $links = $variables['links']; $attributes = $variables['attributes']; $heading = $variables['heading']; @@ -1708,8 +1710,25 @@ $link_element['#ajax'] = $link['ajax']; } - // Handle links. - if (isset($link['route_name']) || isset($link['href'])) { + // Handle links and ensure that the active class is added on the LIs. + if (isset($link['route_name'])) { + $variables = array( + 'options' => array(), + ); + if (!empty($link['language'])) { + $variables['options']['language'] = $link['language']; + } + if (\Drupal::linkGenerator()->isRouteActive($link['route_name'], $link['route_parameters'], $variables)) { + $class[] = 'active'; + } + $item = drupal_render($link_element); + } + elseif (isset($link['href'])) { + $is_current_path = ($link['href'] == current_path() || ($link['href'] == '' && drupal_is_front_page())); + $is_current_language = (empty($link['language']) || $link['language']->id == $language_url->id); + if ($is_current_path && $is_current_language) { + $class[] = 'active'; + } $item = drupal_render($link_element); } // Handle title-only text items. reverted: --- b/core/modules/comment/comment.local_tasks.yml +++ a/core/modules/comment/comment.local_tasks.yml @@ -1,14 +1,14 @@ comment.permalink_tab: + route_name: comment_permalink - route_name: comment.permalink title: 'View comment' tab_root_id: comment.permalink_tab comment.edit_page_tab: + route_name: comment_edit_page - route_name: comment.edit_page title: 'Edit' tab_root_id: comment.permalink_tab weight: 0 comment.confirm_delete_tab: + route_name: comment_confirm_delete - route_name: comment.confirm_delete title: 'Delete' tab_root_id: comment.permalink_tab weight: 10 reverted: --- b/core/modules/language/lib/Drupal/language/Tests/LanguageSwitchingTest.php +++ a/core/modules/language/lib/Drupal/language/Tests/LanguageSwitchingTest.php @@ -72,6 +72,12 @@ foreach ($language_switcher->ul->li as $link) { $classes = explode(" ", (string) $link['class']); list($langcode) = array_intersect($classes, array('en', 'fr')); + if (in_array('active', $classes)) { + $links['active'][] = $langcode; + } + else { + $links['inactive'][] = $langcode; + } $anchor_classes = explode(" ", (string) $link->a['class']); if (in_array('active', $anchor_classes)) { $anchors['active'][] = $langcode; @@ -80,6 +86,7 @@ $anchors['inactive'][] = $langcode; } } + $this->assertIdentical($links, array('active' => array('en'), 'inactive' => array('fr')), 'Only the current language list item is marked as active on the language switcher block.'); $this->assertIdentical($anchors, array('active' => array('en'), 'inactive' => array('fr')), 'Only the current language anchor is marked as active on the language switcher block.'); } diff -u b/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php --- b/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php +++ b/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php @@ -13,6 +13,14 @@ * Tests for common theme functions. */ class FunctionsTest extends WebTestBase { + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('router_test'); + public static function getInfo() { return array( 'name' => 'Theme functions', @@ -158,13 +166,19 @@ 'title' => 'Front page', 'href' => '', ), + 'router-test' => array( + 'title' => 'Test route', + 'route_name' => 'router_test.1', + 'route_parameters' => array(), + ), ); $expected_links = ''; $expected_links .= ''; // Verify that passing a string as heading works. @@ -197,6 +211,7 @@ $expected_links .= ''; $expected_links .= '
  • ' . check_plain('Plain "text"') . '
  • '; $expected_links .= '
  • ' . check_plain('Front page') . '
  • '; + $expected_links .= '
  • ' . check_plain('Test route') . '
  • '; $expected_links .= ''; $expected = $expected_heading . $expected_links; $this->assertThemeOutput('links', $variables, $expected); only in patch2: unchanged: --- a/core/lib/Drupal/Core/Utility/LinkGenerator.php +++ b/core/lib/Drupal/Core/Utility/LinkGenerator.php @@ -119,10 +119,7 @@ public function generate($text, $route_name, array $parameters = array(), array // URL path and query string as the current page. Note that this may be // removed from l() in https://drupal.org/node/1979468 and would be removed // or altered here also. - $variables['url_is_active'] = $route_name == $this->active['route_name'] - // The language of an active link is equal to the current language. - && (empty($variables['options']['language']) || $variables['options']['language']->id == $this->active['language']) - && $full_parameters == $this->active['parameters']; + $variables['url_is_active'] = $this->isRouteActive($route_name, $full_parameters, $variables); // Add the "active" class if appropriate. if ($variables['url_is_active']) { @@ -152,4 +149,16 @@ public function generate($text, $route_name, array $parameters = array(), array return '' . $text . ''; } + /** + * {@inheritdoc} + */ + public function isRouteActive($route_name, array $route_parameters, array $variables) { + $url_is_active = $route_name == $this->active['route_name'] + // The language of an active link is equal to the current language. + && (empty($variables['options']['language']) || $variables['options']['language']->id == $this->active['language']) + && $route_parameters == $this->active['parameters']; + + return $url_is_active; + } + } only in patch2: unchanged: --- a/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php +++ b/core/lib/Drupal/Core/Utility/LinkGeneratorInterface.php @@ -71,4 +71,19 @@ */ public function generate($text, $route_name, array $parameters = array(), array $options = array()); + /** + * Determines whether a given route is the current active route. + * + * @param string $route_name + * The route name to check whether it is the current active one. + * @param array $route_parameters + * The route parameters belonging to $route_name to check. + * @param array $variables + * A link variables array containing the link options. + * + * @return bool + * Returns TRUE if the route matches the current route, otherwise FALSE. + */ + public function isRouteActive($route_name, array $route_parameters, array $variables); + } only in patch2: unchanged: --- a/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php +++ b/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php @@ -333,6 +333,7 @@ public function testGenerateActive() { $request = new Request(array(), array(), array('system_path' => 'test-route-2')); $this->linkGenerator->setRequest($request); $result = $this->linkGenerator->generate('Test', 'test_route_1'); + $this->assertFalse($this->linkGenerator->isRouteActive('test_route_1', array(), array())); $this->assertNotTag(array( 'tag' => 'a', 'attributes' => array('class' => 'active'), @@ -346,6 +347,7 @@ public function testGenerateActive() { $request->attributes->set('_raw_variables', $raw_variables); $this->linkGenerator->setRequest($request); $result = $this->linkGenerator->generate('Test', 'test_route_1'); + $this->assertTrue($this->linkGenerator->isRouteActive('test_route_1', array(), array())); $this->assertTag(array( 'tag' => 'a', 'attributes' => array('class' => 'active'), @@ -353,6 +355,7 @@ public function testGenerateActive() { // Render a link with the same path and language as the current path. $result = $this->linkGenerator->generate('Test', 'test_route_1'); + $this->assertTrue($this->linkGenerator->isRouteActive('test_route_1', array(), array())); $this->assertTag(array( 'tag' => 'a', 'attributes' => array('class' => 'active'), @@ -366,6 +369,7 @@ public function testGenerateActive() { array(), array('language' => new Language(array('id' => 'de'))) ); + $this->assertFalse($this->linkGenerator->isRouteActive('test_route_1', array(), array('options' => array('language' => new Language(array('id' => 'de')))))); $this->assertNotTag(array( 'tag' => 'a', 'attributes' => array('class' => 'active'), @@ -382,6 +386,7 @@ public function testGenerateActive() { array(), array('query' => array('value' => 'example_1') )); + $this->assertTrue($this->linkGenerator->isRouteActive('test_route_3', array('value' => 'example_1'), array())); $this->assertTag(array( 'tag' => 'a', 'attributes' => array('class' => 'active'), @@ -395,6 +400,7 @@ public function testGenerateActive() { array(), array('query' => array('value' => 'example_2')) ); + $this->assertFalse($this->linkGenerator->isRouteActive('test_route_3', array('value' => 'example_2'), array())); $this->assertNotTag(array( 'tag' => 'a', 'attributes' => array('class' => 'active'), @@ -410,6 +416,7 @@ public function testGenerateActive() { array('object' => '1'), array('query' => array('value' => 'example_1')) ); + $this->assertTrue($this->linkGenerator->isRouteActive('test_route_4', array('object' => '1', 'value' => 'example_1'), array())); $this->assertTag(array( 'tag' => 'a', 'attributes' => array('class' => 'active'),