diff --git a/core/includes/theme.inc b/core/includes/theme.inc index 47c99d9..9b33ab9 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -1703,9 +1703,11 @@ function theme_link($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 @@ -1738,13 +1740,22 @@ function theme_link($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']; + + // Remove 'links' from the attributes array. This is added through + // template_preprocess() but we do not need it. + // @todo Remove after http://drupal.org/node/1938430 is resolved. + if (isset($variables['attributes']['class'][0]) && $variables['attributes']['class'][0] == 'links') { + unset($variables['attributes']['class'][0]); + if (empty($variables['attributes']['class'])) { + unset($variables['attributes']['class']); + } + } + $variables['attributes'] = new Attribute($variables['attributes']); if (!empty($links)) { // Prepend the heading to the list, if any. @@ -1755,21 +1766,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 .= ''; + // 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) { @@ -1786,7 +1793,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())); @@ -1795,45 +1801,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; } /** @@ -3155,6 +3153,7 @@ function drupal_common_theme() { ), 'links' => array( 'variables' => array('links' => array(), 'attributes' => array('class' => array('links')), 'heading' => array()), + 'template' => 'links', ), 'dropbutton_wrapper' => array( 'render element' => 'element', 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 1faf6d8..3240704 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(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..6e2d4c7 --- /dev/null +++ b/core/modules/system/templates/links.html.twig @@ -0,0 +1,65 @@ +{# +/** + * @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. + * If the heading is an array, it can have the following elements: + * - text: The heading text. + * - level: The heading level (e.g. 'h2', 'h3'). + * - attributes: (optional) A keyed array 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 'element-invisible' 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() + * @see template_preprocess_links() + * + * @ingroup themeable + */ + @todo revisit once http://drupal.org/node/1842034 is resolved. +#} +{% spaceless %} +{% if links %} + {% if heading %} + {% if heading.level %} + <{{ heading.level }}{{ heading.attributes }}>{{ heading.text }} + {% 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 %}