diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 769e34c..665ca73 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -568,9 +568,8 @@ function template_preprocess_datetime_wrapper(&$variables) { * * @param array $variables * An associative array containing: - * - links: An associative array of links to be themed. The key for each link - * is used as its CSS class. Each link should be itself an array, with the - * following elements: + * - links: An array of links to be themed. Each link should be itself an + * array, with the following elements: * - title: The link text. * - url: (optional) The url object to link to. If omitted, no a tag is * printed out. diff --git a/core/modules/system/src/Tests/Theme/FunctionsTest.php b/core/modules/system/src/Tests/Theme/FunctionsTest.php index 5e31422..e64f10e 100644 --- a/core/modules/system/src/Tests/Theme/FunctionsTest.php +++ b/core/modules/system/src/Tests/Theme/FunctionsTest.php @@ -290,6 +290,127 @@ function testLinks() { } /** + * Tests links.html.twig. + */ + function testIndexedKeyedLinks() { + // Turn off the query for the + // \Drupal\Core\Utility\LinkGeneratorInterface::generate() method to compare + // the active link correctly. + $original_query = \Drupal::request()->query->all(); + \Drupal::request()->query->replace([]); + // Verify that empty variables produce no output. + $variables = []; + $expected = ''; + $this->assertThemeOutput('links', $variables, $expected, 'Empty %callback generates no output.'); + + $variables = []; + $variables['heading'] = 'Some title'; + $expected = ''; + $this->assertThemeOutput('links', $variables, $expected, 'Empty %callback with heading generates no output.'); + + // Verify that a list of links is properly rendered. + $variables = []; + $variables['attributes'] = ['id' => 'somelinks']; + $variables['links'] = array( + array( + 'title' => 'A ', + 'url' => Url::fromUri('base:a/link'), + ), + array( + 'title' => 'Plain "text"', + ), + array( + 'title' => SafeMarkup::format('@text', array('@text' => 'potentially unsafe text that be escaped')), + ), + array( + 'title' => 'Front page', + 'url' => Url::fromRoute(''), + ), + array( + 'title' => 'Test route', + 'url' => Url::fromRoute('router_test.1'), + ), + array( + 'title' => 'Query test route', + 'url' => Url::fromRoute('router_test.1'), + 'query' => array( + 'key' => 'value', + ) + ), + ); + + $expected_links = ''; + $expected_links .= ''; + + // Verify that passing a string as heading works. + $variables['heading'] = 'Links heading'; + $expected_heading = '

Links heading

'; + $expected = $expected_heading . $expected_links; + $this->assertThemeOutput('links', $variables, $expected); + + // Restore the original request's query. + \Drupal::request()->query->replace($original_query); + + // Verify that passing an array as heading works (core support). + $variables['heading'] = [ + 'text' => 'Links heading', + 'level' => 'h3', + 'attributes' => ['class' => ['heading']], + ]; + $expected_heading = '

Links heading

'; + $expected = $expected_heading . $expected_links; + $this->assertThemeOutput('links', $variables, $expected); + + // Verify that passing attributes for the heading works. + $variables['heading'] = ['text' => 'Links heading', 'level' => 'h3', 'attributes' => ['id' => 'heading']]; + $expected_heading = '

Links heading

'; + $expected = $expected_heading . $expected_links; + $this->assertThemeOutput('links', $variables, $expected); + + // Verify that passing attributes for the links work. + $variables['links'][1]['attributes'] = [ + 'class' => ['a/class'], + ]; + $expected_links = ''; + $expected_links .= ''; + $expected = $expected_heading . $expected_links; + $this->assertThemeOutput('links', $variables, $expected); + + // Verify the data- attributes for setting the "active" class on links. + \Drupal::currentUser()->setAccount(new UserSession(array('uid' => 1))); + $variables['set_active_class'] = TRUE; + $expected_links = ''; + $expected_links .= ''; + $expected = $expected_heading . $expected_links; + $this->assertThemeOutput('links', $variables, $expected); + } + + /** * Test the use of drupal_pre_render_links() on a nested array of links. */ function testDrupalPreRenderLinks() { diff --git a/core/modules/system/templates/links.html.twig b/core/modules/system/templates/links.html.twig index 86713b5..77e7260 100644 --- a/core/modules/system/templates/links.html.twig +++ b/core/modules/system/templates/links.html.twig @@ -13,7 +13,6 @@ * to l() as its $options parameter. * - attributes: (optional) HTML attributes for the anchor, or for the * tag if no 'href' is supplied. - * - link_key: The link CSS class. * - heading: (optional) A heading to precede the links. * - text: The heading text. * - level: The heading level (e.g. 'h2', 'h3'). @@ -43,8 +42,8 @@ {%- endif -%} {%- endif -%} - {%- for key, item in links -%} - + {%- for item in links -%} + {%- if item.link -%} {{ item.link }} {%- elseif item.text_attributes -%} diff --git a/core/themes/classy/templates/content/links--node.html.twig b/core/themes/classy/templates/content/links--node.html.twig index f4c3d72..a7b91e7 100644 --- a/core/themes/classy/templates/content/links--node.html.twig +++ b/core/themes/classy/templates/content/links--node.html.twig @@ -13,7 +13,6 @@ * to l() as its $options parameter. * - attributes: (optional) HTML attributes for the anchor, or for the * tag if no 'href' is supplied. - * - link_key: The link CSS class. * - heading: (optional) A heading to precede the links. * - text: The heading text. * - level: The heading level (e.g. 'h2', 'h3'). diff --git a/core/themes/classy/templates/navigation/links.html.twig b/core/themes/classy/templates/navigation/links.html.twig index f82f41a..c1bff6b 100644 --- a/core/themes/classy/templates/navigation/links.html.twig +++ b/core/themes/classy/templates/navigation/links.html.twig @@ -13,7 +13,6 @@ * to l() as its $options parameter. * - attributes: (optional) HTML attributes for the anchor, or for the * tag if no 'href' is supplied. - * - link_key: The link CSS class. * - heading: (optional) A heading to precede the links. * - text: The heading text. * - level: The heading level (e.g. 'h2', 'h3'). @@ -41,8 +40,8 @@ {%- endif -%} {%- endif -%} - {%- for key, item in links -%} - + {%- for item in links -%} + {%- if item.link -%} {{ item.link }} {%- elseif item.text_attributes -%} diff --git a/core/themes/stable/stable.theme b/core/themes/stable/stable.theme new file mode 100644 index 0000000..663667a --- /dev/null +++ b/core/themes/stable/stable.theme @@ -0,0 +1,20 @@ + $value) { + if (!is_numeric($key)) { + $class = Html::getClass($key); + $variables['links'][$key]['attributes']->addClass($class); + } + } + } +} diff --git a/core/themes/stable/templates/navigation/links.html.twig b/core/themes/stable/templates/navigation/links.html.twig index f82f41a..c1bff6b 100644 --- a/core/themes/stable/templates/navigation/links.html.twig +++ b/core/themes/stable/templates/navigation/links.html.twig @@ -13,7 +13,6 @@ * to l() as its $options parameter. * - attributes: (optional) HTML attributes for the anchor, or for the * tag if no 'href' is supplied. - * - link_key: The link CSS class. * - heading: (optional) A heading to precede the links. * - text: The heading text. * - level: The heading level (e.g. 'h2', 'h3'). @@ -41,8 +40,8 @@ {%- endif -%} {%- endif -%} - {%- for key, item in links -%} - + {%- for item in links -%} + {%- if item.link -%} {{ item.link }} {%- elseif item.text_attributes -%}