Commit 4f6ab6e7 authored by catch's avatar catch
Browse files

Issue #2402165 by joelpittet, hass, madhavvyas: #theme => 'links' renders <li...

Issue #2402165 by joelpittet, hass, madhavvyas: #theme => 'links' renders <li class="_"> when the #links array is not associative
parent 585087f5
......@@ -583,9 +583,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.
......
......@@ -289,6 +289,127 @@ function testLinks() {
$this->assertThemeOutput('links', $variables, $expected);
}
/**
* Tests links.html.twig using links with indexed keys.
*/
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 <link>',
'url' => Url::fromUri('base:a/link'),
),
array(
'title' => 'Plain "text"',
),
array(
'title' => SafeMarkup::format('<span class="unescaped">@text</span>', array('@text' => 'potentially unsafe text that <should> be escaped')),
),
array(
'title' => 'Front page',
'url' => Url::fromRoute('<front>'),
),
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 .= '<ul id="somelinks">';
$expected_links .= '<li><a href="' . Url::fromUri('base:a/link')->toString() . '">' . Html::escape('A <link>') . '</a></li>';
$expected_links .= '<li>' . Html::escape('Plain "text"') . '</li>';
$expected_links .= '<li><span class="unescaped">' . Html::escape('potentially unsafe text that <should> be escaped') . '</span></li>';
$expected_links .= '<li><a href="' . Url::fromRoute('<front>')->toString() . '">' . Html::escape('Front page') . '</a></li>';
$expected_links .= '<li><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '">' . Html::escape('Test route') . '</a></li>';
$query = ['key' => 'value'];
$expected_links .= '<li><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '">' . Html::escape('Query test route') . '</a></li>';
$expected_links .= '</ul>';
// Verify that passing a string as heading works.
$variables['heading'] = 'Links heading';
$expected_heading = '<h2>Links heading</h2>';
$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 = '<h3 class="heading">Links heading</h3>';
$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 = '<h3 id="heading">Links heading</h3>';
$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 .= '<ul id="somelinks">';
$expected_links .= '<li><a href="' . Url::fromUri('base:a/link')->toString() . '">' . Html::escape('A <link>') . '</a></li>';
$expected_links .= '<li><span class="a/class">' . Html::escape('Plain "text"') . '</span></li>';
$expected_links .= '<li><span class="unescaped">' . Html::escape('potentially unsafe text that <should> be escaped') . '</span></li>';
$expected_links .= '<li><a href="' . Url::fromRoute('<front>')->toString() . '">' . Html::escape('Front page') . '</a></li>';
$expected_links .= '<li><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '">' . Html::escape('Test route') . '</a></li>';
$query = ['key' => 'value'];
$expected_links .= '<li><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '">' . Html::escape('Query test route') . '</a></li>';
$expected_links .= '</ul>';
$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 .= '<ul id="somelinks">';
$expected_links .= '<li><a href="' . Url::fromUri('base:a/link')->toString() . '">' . Html::escape('A <link>') . '</a></li>';
$expected_links .= '<li><span class="a/class">' . Html::escape('Plain "text"') . '</span></li>';
$expected_links .= '<li><span class="unescaped">' . Html::escape('potentially unsafe text that <should> be escaped') . '</span></li>';
$expected_links .= '<li data-drupal-link-system-path="&lt;front&gt;"><a href="' . Url::fromRoute('<front>')->toString() . '" data-drupal-link-system-path="&lt;front&gt;">' . Html::escape('Front page') . '</a></li>';
$expected_links .= '<li data-drupal-link-system-path="router_test/test1"><a href="' . \Drupal::urlGenerator()->generate('router_test.1') . '" data-drupal-link-system-path="router_test/test1">' . Html::escape('Test route') . '</a></li>';
$query = ['key' => 'value'];
$encoded_query = Html::escape(Json::encode($query));
$expected_links .= '<li data-drupal-link-query="' . $encoded_query . '" data-drupal-link-system-path="router_test/test1"><a href="' . \Drupal::urlGenerator()->generate('router_test.1', $query) . '" data-drupal-link-query="' . $encoded_query . '" data-drupal-link-system-path="router_test/test1">' . Html::escape('Query test route') . '</a></li>';
$expected_links .= '</ul>';
$expected = $expected_heading . $expected_links;
$this->assertThemeOutput('links', $variables, $expected);
}
/**
* Test the use of drupal_pre_render_links() on a nested array of links.
*/
......
......@@ -13,7 +13,6 @@
* to l() as its $options parameter.
* - attributes: (optional) HTML attributes for the anchor, or for the <span>
* 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 -%}
<ul{{ attributes }}>
{%- for key, item in links -%}
<li{{ item.attributes.addClass(key|clean_class) }}>
{%- for item in links -%}
<li{{ item.attributes }}>
{%- if item.link -%}
{{ item.link }}
{%- elseif item.text_attributes -%}
......
......@@ -156,11 +156,10 @@ protected function doTestRenderedOutput(AccountInterface $account, $check_cache
$expected = $access ? "<a href=\"$node_url/delete?destination=/\" hreflang=\"en\">delete</a>" : "";
$output = $view->style_plugin->getField($index, 'delete_node');
$this->assertEqual($output, $expected);
$expected = $access ? " <div class=\"dropbutton-wrapper\"><div class=\"dropbutton-widget\"><ul class=\"dropbutton\">" .
"<li class=\"edit\"><a href=\"$node_url/edit?destination=/\" hreflang=\"en\">Edit</a></li>" .
"<li class=\"delete\"><a href=\"$node_url/delete?destination=/\" hreflang=\"en\">Delete</a></li>" .
"</ul></div></div>" : "";
$expected = $access ? ' <div class="dropbutton-wrapper"><div class="dropbutton-widget"><ul class="dropbutton">' .
'<li><a href="' . $node_url . '/edit?destination=/" hreflang="en">Edit</a></li>' .
'<li><a href="' . $node_url . '/delete?destination=/" hreflang="en">Delete</a></li>' .
'</ul></div></div>' : '';
$output = $view->style_plugin->getField($index, 'operations');
$this->assertEqual($output, $expected);
......
......@@ -13,7 +13,6 @@
* to l() as its $options parameter.
* - attributes: (optional) HTML attributes for the anchor, or for the <span>
* 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').
......
......@@ -13,7 +13,6 @@
* to l() as its $options parameter.
* - attributes: (optional) HTML attributes for the anchor, or for the <span>
* 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 -%}
<ul{{ attributes }}>
{%- for key, item in links -%}
<li{{ item.attributes.addClass(key|clean_class) }}>
{%- for item in links -%}
<li{{ item.attributes }}>
{%- if item.link -%}
{{ item.link }}
{%- elseif item.text_attributes -%}
......
<?php
/**
* @file
* Functions to support theming in the Stable theme.
*/
use Drupal\Component\Utility\Html;
/**
* Implements template_preprocess_links().
*/
function stable_preprocess_links(&$variables) {
// @deprecated in Drupal 8.0.x and will be removed before 9.0.0. This feature
// of adding a class based on the associative key can cause CSS class name
// conflicts.
if (!empty($variables['links'])) {
foreach ($variables['links'] as $key => $value) {
if (!is_numeric($key)) {
$class = Html::getClass($key);
$variables['links'][$key]['attributes']->addClass($class);
}
}
}
}
......@@ -13,7 +13,6 @@
* to l() as its $options parameter.
* - attributes: (optional) HTML attributes for the anchor, or for the <span>
* 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 -%}
<ul{{ attributes }}>
{%- for key, item in links -%}
<li{{ item.attributes.addClass(key|clean_class) }}>
{%- for item in links -%}
<li{{ item.attributes }}>
{%- if item.link -%}
{{ item.link }}
{%- elseif item.text_attributes -%}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment