diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 330c448..af551ef 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -1612,9 +1612,11 @@ function theme_status_messages($variables) {
}
/**
- * Returns HTML for a set of links.
+ * Prepares variables for links templates.
*
- * @param $variables
+ * Default template: links.html.twig.
+ *
+ * @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
@@ -1647,13 +1649,10 @@ function theme_status_messages($variables) {
* http://juicystudio.com/article/screen-readers-display-none.php and
* http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
*/
-function theme_links($variables) {
+function template_preprocess_links(&$variables) {
$language_url = language(Language::TYPE_URL);
-
$links = $variables['links'];
- $attributes = $variables['attributes'];
- $heading = $variables['heading'];
- $output = '';
+ $heading = &$variables['heading'];
if (!empty($links)) {
// Prepend the heading to the list, if any.
@@ -1664,21 +1663,17 @@ function theme_links($variables) {
}
// Merge in default array properties into $heading.
$heading += array(
- 'level' => 'h2',
'attributes' => array(),
);
// @todo Remove backwards compatibility for $heading['class'].
if (isset($heading['class'])) {
$heading['attributes']['class'] = $heading['class'];
}
-
- $output .= '<' . $heading['level'] . new Attribute($heading['attributes']) . '>';
- $output .= check_plain($heading['text']);
- $output .= '' . $heading['level'] . '>';
+ // Convert the attributes array into an attributes object.
+ $heading['attributes'] = new Attribute($heading['attributes']);
+ $heading['text'] = check_plain($heading['text']);
}
- $output .= '
';
-
$num_links = count($links);
$i = 0;
foreach ($links as $key => $link) {
@@ -1695,7 +1690,6 @@ function theme_links($variables) {
if ($i == $num_links) {
$class[] = 'last';
}
-
// Handle links.
if (isset($link['href'])) {
$is_current_path = ($link['href'] == current_path() || ($link['href'] == '' && drupal_is_front_page()));
@@ -1704,45 +1698,37 @@ function theme_links($variables) {
$class[] = 'active';
}
// @todo Reconcile Views usage of 'ajax' as a boolean with the rest of
- // core's usage of it as an array.
+ // core's usage of it as an array.
+ $item = array(
+ '#type' => 'link',
+ '#title' => $link['title'],
+ '#href' => $link['href'],
+ );
if (isset($link['ajax']) && is_array($link['ajax'])) {
- // To attach Ajax behavior, render a link element, rather than just
- // call l().
- $link_element = array(
- '#type' => 'link',
- '#title' => $link['title'],
- '#href' => $link['href'],
+ $item += array(
'#ajax' => $link['ajax'],
'#options' => array_diff_key($link, drupal_map_assoc(array('title', 'href', 'ajax'))),
);
- $item = drupal_render($link_element);
}
else {
- // Pass in $link as $options, they share the same keys.
- $item = l($link['title'], $link['href'], $link);
+ $item += array(
+ '#options' => array_diff_key($link, drupal_map_assoc(array('title', 'href'))),
+ );
}
+ $variables['links'][$key]['link'] = $item;
}
- // Handle title-only text items.
- else {
- // Merge in default array properties into $link.
- $link += array(
- 'html' => FALSE,
- );
- $item = ($link['html'] ? $link['title'] : check_plain($link['title']));
- if (isset($link['attributes'])) {
- $item = '' . $item . '';
- }
+
+ // Handle text.
+ $text = (!empty($link['html']) ? $link['title'] : check_plain($link['title']));
+ $variables['links'][$key]['text'] = $text;
+ if (isset($link['attributes'])) {
+ $variables['links'][$key]['text_attributes'] = new Attribute($link['attributes']);
}
- $output .= '- $class)) . '>';
- $output .= $item;
- $output .= '
';
+ // Handle list item attributes.
+ $variables['links'][$key]['attributes'] = new Attribute(array('class' => $class));
}
-
- $output .= '
';
}
-
- return $output;
}
/**
@@ -3025,6 +3011,7 @@ function drupal_common_theme() {
),
'links' => array(
'variables' => array('links' => array(), 'attributes' => array('class' => array('links')), 'heading' => array()),
+ 'template' => 'links',
),
'dropbutton_wrapper' => array(
'variables' => array('children' => NULL),
diff --git a/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php b/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php
index 9330299..ef73b59 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Theme/FunctionsTest.php
@@ -143,6 +143,9 @@ function testLinks() {
// because the current path is different when running tests manually via
// simpletest.module ('batch') and via the testing framework ('').
_current_path(\Drupal::config('system.site')->get('page.front'));
+ // Release the static variable because it's not getting released before
+ // the tests run.
+ drupal_static_reset('drupal_is_front_page');
// Verify that a list of links is properly rendered.
$variables = array();
diff --git a/core/modules/system/templates/links.html.twig b/core/modules/system/templates/links.html.twig
new file mode 100644
index 0000000..0be0e77
--- /dev/null
+++ b/core/modules/system/templates/links.html.twig
@@ -0,0 +1,62 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a set of links.
+ *
+ * Available variables:
+ * - attributes: Attributes for the UL containing the list of links.
+ * - links: Links to be output.
+ * Each link will have the following elements:
+ * - title: The link text.
+ * - href: The link URL. If omitted, the 'title' is shown as a plain text
+ * item in the links list. If 'href' is supplied, the entire link is passed
+ * to l() as its $options parameter.
+ * - html: (optional) Whether or not 'title' is HTML. If set, the title will
+ * not be passed through check_plain().
+ * - attributes: (optional) HTML attributes for the anchor, or for the
+ * tag if no 'href' is supplied.
+ * - heading: (optional) A heading to precede the links. May be an associative
+ * array or a string.
+ * - text: The heading text.
+ * - level: The heading level (e.g. 'h2', 'h3').
+ * - attributes: (optional) A keyed list of attributes for the heading.
+ * If the heading is a string, it will be used as the text of the heading and
+ * the level will default to 'h2'.
+ *
+ * Headings should be used on navigation menus and any list of links that
+ * consistently appears on multiple pages. To make the heading invisible use
+ * the 'visually-hidden' CSS class. Do not use 'display:none', which
+ * removes it from screen-readers and assistive technology. Headings allow
+ * screen-reader and keyboard only users to navigate to or skip the links.
+ * See http://juicystudio.com/article/screen-readers-display-none.php and
+ * http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
+ *
+ * @see template_preprocess_links()
+ *
+ * @ingroup themeable
+ */
+#}
+{% spaceless %}
+ {% if links %}
+ {% if heading %}
+ {% if heading.level %}
+ <{{ heading.level }}{{ heading.attributes }}>{{ heading.text }}{{ heading.level }}>
+ {% else %}
+ {{ heading.text }}
+ {% endif %}
+ {% endif %}
+
+ {% for item in links %}
+ -
+ {% if item.link %}
+ {{ item.link }}
+ {% elseif item.text_attributes %}
+ {{ item.text }}
+ {% else %}
+ {{ item.text }}
+ {% endif %}
+
+ {% endfor %}
+
+ {% endif %}
+{% endspaceless %}