Commit 5fb188f2 authored by catch's avatar catch

Issue #98696 by sun, floretan, rszrama, zeta ζ, marvil07: Fixed various bugs in theme_links().

parent a3ebad06
......@@ -6647,7 +6647,7 @@ function drupal_common_theme() {
'variables' => array('text' => NULL, 'path' => NULL, 'options' => array()),
),
'links' => array(
'variables' => array('links' => NULL, 'attributes' => array('class' => array('links')), 'heading' => array()),
'variables' => array('links' => array(), 'attributes' => array('class' => array('links')), 'heading' => array()),
),
'image' => array(
// HTML 4 and XHTML 1.0 always require an alt attribute. The HTML 5 draft
......
......@@ -1561,73 +1561,79 @@ function theme_link($variables) {
* http://www.w3.org/TR/WCAG-TECHS/H42.html for more information.
*/
function theme_links($variables) {
global $language_url;
$links = $variables['links'];
$attributes = $variables['attributes'];
$heading = $variables['heading'];
global $language_url;
$output = '';
if (count($links) > 0) {
$output = '';
// Treat the heading first if it is present to prepend it to the
// list of links.
if (!empty($links)) {
// Prepend the heading to the list, if any.
if (!empty($heading)) {
// Convert a string heading into an array, using a H2 tag by default.
if (is_string($heading)) {
// Prepare the array that will be used when the passed heading
// is a string.
$heading = array(
'text' => $heading,
// Set the default level of the heading.
'level' => 'h2',
);
$heading = array('text' => $heading);
}
$output .= '<' . $heading['level'];
if (!empty($heading['class'])) {
$output .= drupal_attributes(array('class' => $heading['class']));
// 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 .= '>' . check_plain($heading['text']) . '</' . $heading['level'] . '>';
$output .= '<' . $heading['level'] . drupal_attributes($heading['attributes']) . '>';
$output .= check_plain($heading['text']);
$output .= '</' . $heading['level'] . '>';
}
$output .= '<ul' . drupal_attributes($attributes) . '>';
$num_links = count($links);
$i = 1;
$i = 0;
foreach ($links as $key => $link) {
$class = array($key);
$i++;
// Add first, last and active classes to the list of links to help out themers.
$class = array();
// Use the array key as class name.
$class[] = drupal_html_class($key);
// Add odd/even, first, and last classes.
$class[] = ($i % 2 ? 'odd' : 'even');
if ($i == 1) {
$class[] = 'first';
}
if ($i == $num_links) {
$class[] = 'last';
}
if (isset($link['href']) && ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()))
&& (empty($link['language']) || $link['language']->language == $language_url->language)) {
$class[] = 'active';
}
$output .= '<li' . drupal_attributes(array('class' => $class)) . '>';
// Handle links.
if (isset($link['href'])) {
$is_current_path = ($link['href'] == $_GET['q'] || ($link['href'] == '<front>' && drupal_is_front_page()));
$is_current_language = (empty($link['language']) || $link['language']->language == $language_url->language);
if ($is_current_path && $is_current_language) {
$class[] = 'active';
}
// Pass in $link as $options, they share the same keys.
$output .= l($link['title'], $link['href'], $link);
$item = l($link['title'], $link['href'], $link);
}
elseif (!empty($link['title'])) {
// Some links are actually not links, but we wrap these in <span> for adding title and class attributes.
if (empty($link['html'])) {
$link['title'] = check_plain($link['title']);
}
$span_attributes = '';
if (isset($link['attributes'])) {
$span_attributes = drupal_attributes($link['attributes']);
}
$output .= '<span' . $span_attributes . '>' . $link['title'] . '</span>';
// Handle title-only text items.
else {
// Merge in default array properties into $link.
$link += array(
'html' => FALSE,
'attributes' => array(),
);
$item = '<span' . drupal_attributes($link['attributes']) . '>';
$item .= ($link['html'] ? $link['title'] : check_plain($link['title']));
$item .= '</span>';
}
$i++;
$output .= "</li>\n";
$output .= '<li' . drupal_attributes(array('class' => $class)) . '>';
$output .= $item;
$output .= '</li>';
}
$output .= '</ul>';
......
......@@ -246,6 +246,69 @@ class ThemeFunctionsTestCase extends DrupalWebTestCase {
$this->assertThemeOutput('item_list', $variables, $expected);
}
/**
* Tests theme_links().
*/
function testLinks() {
// Verify that empty variables produce no output.
$variables = array();
$expected = '';
$this->assertThemeOutput('links', $variables, $expected, 'Empty %callback generates no output.');
$variables = array();
$variables['heading'] = 'Some title';
$expected = '';
$this->assertThemeOutput('links', $variables, $expected, 'Empty %callback with heading generates no output.');
// Set the current path to the front page path.
// Required to verify the "active" class in expected links below, and
// because the current path is different when running tests manually via
// simpletest.module ('batch') and via the testing framework ('').
$_GET['q'] = variable_get('site_frontpage', 'node');
// Verify that a list of links is properly rendered.
$variables = array();
$variables['attributes'] = array('id' => 'somelinks');
$variables['links'] = array(
'a link' => array(
'title' => 'A <link>',
'href' => 'a/link',
),
'plain text' => array(
'title' => 'Plain "text"',
),
'front page' => array(
'title' => 'Front page',
'href' => '<front>',
),
);
$expected_links = '';
$expected_links .= '<ul id="somelinks">';
$expected_links .= '<li class="a-link odd first"><a href="' . url('a/link') . '">' . check_plain('A <link>') . '</a></li>';
$expected_links .= '<li class="plain-text even"><span>' . check_plain('Plain "text"') . '</span></li>';
$expected_links .= '<li class="front-page odd last active"><a href="' . url('<front>') . '" class="active">' . check_plain('Front page') . '</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);
// Verify that passing an array as heading works (core support).
$variables['heading'] = array('text' => 'Links heading', 'level' => 'h3', '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'] = array('text' => 'Links heading', 'level' => 'h3', 'attributes' => array('id' => 'heading'));
$expected_heading = '<h3 id="heading">Links heading</h3>';
$expected = $expected_heading . $expected_links;
$this->assertThemeOutput('links', $variables, $expected);
}
/**
* Asserts themed output.
*
......@@ -271,19 +334,6 @@ class ThemeFunctionsTestCase extends DrupalWebTestCase {
$message = t($message, array('%callback' => 'theme_' . $callback . '()'));
$this->assertIdentical($output, $expected, $message);
}
}
/**
* Unit tests for theme_links().
*/
class ThemeLinksTest extends DrupalWebTestCase {
public static function getInfo() {
return array(
'name' => 'Links',
'description' => 'Test the theme_links() function and rendering groups of links.',
'group' => 'Theme',
);
}
/**
* Test the use of drupal_pre_render_links() on a nested array of links.
......
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