From 4b2478249b5b54cd603812af2bcb4461b8c64d31 Mon Sep 17 00:00:00 2001 From: Nathaniel <catch@35733.no-reply.drupal.org> Date: Wed, 28 Sep 2011 12:00:18 +0900 Subject: [PATCH] =?UTF-8?q?Issue=20#256827=20by=20sun,=20zeta=20=CE=B6:=20?= =?UTF-8?q?Fixed=20Various=20bugs=20in=20theme=5Fitem=5Flist().?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- includes/common.inc | 2 +- includes/theme.inc | 88 ++++++++++++++---------- modules/simpletest/tests/theme.test | 101 +++++++++++++++++++++++----- 3 files changed, 141 insertions(+), 50 deletions(-) diff --git a/includes/common.inc b/includes/common.inc index 581e1150c085..dd4a2fd8799b 100644 --- a/includes/common.inc +++ b/includes/common.inc @@ -6459,7 +6459,7 @@ function drupal_common_theme() { 'variables' => array('type' => MARK_NEW), ), 'item_list' => array( - 'variables' => array('items' => array(), 'title' => NULL, 'type' => 'ul', 'attributes' => array()), + 'variables' => array('items' => array(), 'title' => '', 'type' => 'ul', 'attributes' => array()), ), 'more_help_link' => array( 'variables' => array('url' => NULL), diff --git a/includes/theme.inc b/includes/theme.inc index 1f991ea6f19d..b85a35cfb562 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -1793,12 +1793,14 @@ function theme_mark($variables) { * * @param $variables * An associative array containing: - * - items: An array of items to be displayed in the list. If an item is a - * string, then it is used as is. If an item is an array, then the "data" - * element of the array is used as the contents of the list item. If an item - * is an array with a "children" element, those children are displayed in a - * nested list. All other elements are treated as attributes of the list - * item element. + * - items: A list of items to render. String values are rendered as is. Each + * item can also be an associative array containing: + * - data: The string content of the list item. + * - children: A list of nested child items to render that behave + * identically to 'items', but any non-numeric string keys are treated as + * HTML attributes for the child list that wraps 'children'. + * Any other key/value pairs are used as HTML attributes for the list item + * in 'data'. * - title: The title of the list. * - type: The type of list to return (e.g. "ul", "ol"). * - attributes: The attributes applied to the list element. @@ -1807,51 +1809,69 @@ function theme_item_list($variables) { $items = $variables['items']; $title = $variables['title']; $type = $variables['type']; - $attributes = $variables['attributes']; + $list_attributes = $variables['attributes']; - $output = '<div class="item-list">'; - if (isset($title)) { - $output .= '<h3>' . $title . '</h3>'; - } + $output = ''; + if ($items) { + $output .= '<' . $type . drupal_attributes($list_attributes) . '>'; - if (!empty($items)) { - $output .= "<$type" . drupal_attributes($attributes) . '>'; $num_items = count($items); - foreach ($items as $i => $item) { + $i = 0; + foreach ($items as $key => $item) { + $i++; $attributes = array(); - $children = array(); - $data = ''; + if (is_array($item)) { - foreach ($item as $key => $value) { - if ($key == 'data') { - $data = $value; - } - elseif ($key == 'children') { - $children = $value; - } - else { - $attributes[$key] = $value; + $value = ''; + if (isset($item['data'])) { + $value .= $item['data']; + } + $attributes = array_diff_key($item, array('data' => 0, 'children' => 0)); + + // Append nested child list, if any. + if (isset($item['children'])) { + // HTML attributes for the outer list are defined in the 'attributes' + // theme variable, but not inherited by children. For nested lists, + // all non-numeric keys in 'children' are used as list attributes. + $child_list_attributes = array(); + foreach ($item['children'] as $child_key => $child_item) { + if (is_string($child_key)) { + $child_list_attributes[$child_key] = $child_item; + unset($item['children'][$child_key]); + } } + $value .= theme('item_list', array( + 'items' => $item['children'], + 'type' => $type, + 'attributes' => $child_list_attributes, + )); } } else { - $data = $item; - } - if (count($children) > 0) { - // Render nested list. - $data .= theme_item_list(array('items' => $children, 'title' => NULL, 'type' => $type, 'attributes' => $attributes)); + $value = $item; } - if ($i == 0) { + + $attributes['class'][] = ($i % 2 ? 'odd' : 'even'); + if ($i == 1) { $attributes['class'][] = 'first'; } - if ($i == $num_items - 1) { + if ($i == $num_items) { $attributes['class'][] = 'last'; } - $output .= '<li' . drupal_attributes($attributes) . '>' . $data . "</li>\n"; + + $output .= '<li' . drupal_attributes($attributes) . '>' . $value . '</li>'; } $output .= "</$type>"; } - $output .= '</div>'; + + // Only output the list container and title, if there are any list items. + if ($output !== '') { + if ($title !== '') { + $title = '<h3>' . $title . '</h3>'; + } + $output = '<div class="item-list">' . $title . $output . '</div>'; + } + return $output; } diff --git a/modules/simpletest/tests/theme.test b/modules/simpletest/tests/theme.test index 53557e361a03..d064359f253a 100644 --- a/modules/simpletest/tests/theme.test +++ b/modules/simpletest/tests/theme.test @@ -164,30 +164,101 @@ class ThemeTableUnitTest extends DrupalWebTestCase { } /** - * Unit tests for theme_item_list(). + * Tests for common theme functions. */ -class ThemeItemListUnitTest extends DrupalWebTestCase { +class ThemeFunctionsTestCase extends DrupalWebTestCase { + protected $profile = 'testing'; + public static function getInfo() { return array( - 'name' => 'Theme item list', - 'description' => 'Test the theme_item_list() function.', + 'name' => 'Theme functions', + 'description' => 'Tests common theme functions.', 'group' => 'Theme', ); } /** - * Test nested list rendering. + * Tests theme_item_list(). */ - function testNestedList() { - $items = array('a', array('data' => 'b', 'children' => array('c', 'd')), 'e'); - $expected = '<div class="item-list"><ul><li class="first">a</li> -<li>b<div class="item-list"><ul><li class="first">c</li> -<li class="last">d</li> -</ul></div></li> -<li class="last">e</li> -</ul></div>'; - $output = theme('item_list', array('items' => $items)); - $this->assertIdentical($expected, $output, 'Nested list is rendered correctly.'); + function testItemList() { + // Verify that empty variables produce no output. + $variables = array(); + $expected = ''; + $this->assertThemeOutput('item_list', $variables, $expected, 'Empty %callback generates no output.'); + + $variables = array(); + $variables['title'] = 'Some title'; + $expected = ''; + $this->assertThemeOutput('item_list', $variables, $expected, 'Empty %callback with title generates no output.'); + + // Verify nested item lists. + $variables = array(); + $variables['title'] = 'Some title'; + $variables['attributes'] = array( + 'id' => 'parentlist', + ); + $variables['items'] = array( + 'a', + array( + 'data' => 'b', + 'children' => array( + 'c', + // Nested children may use additional attributes. + array( + 'data' => 'd', + 'class' => array('dee'), + ), + // Any string key is treated as child list attribute. + 'id' => 'childlist', + ), + // Any other keys are treated as item attributes. + 'id' => 'bee', + ), + array( + 'data' => 'e', + 'id' => 'E', + ), + ); + $inner = '<div class="item-list"><ul id="childlist">'; + $inner .= '<li class="odd first">c</li>'; + $inner .= '<li class="dee even last">d</li>'; + $inner .= '</ul></div>'; + + $expected = '<div class="item-list">'; + $expected .= '<h3>Some title</h3>'; + $expected .= '<ul id="parentlist">'; + $expected .= '<li class="odd first">a</li>'; + $expected .= '<li id="bee" class="even">b' . $inner . '</li>'; + $expected .= '<li id="E" class="odd last">e</li>'; + $expected .= '</ul></div>'; + + $this->assertThemeOutput('item_list', $variables, $expected); + } + + /** + * Asserts themed output. + * + * @param $callback + * The name of the theme function to invoke; e.g. 'links' for theme_links(). + * @param $variables + * An array of variables to pass to the theme function. + * @param $expected + * The expected themed output string. + * @param $message + * (optional) An assertion message. + */ + protected function assertThemeOutput($callback, array $variables = array(), $expected, $message = '') { + $output = theme($callback, $variables); + $this->verbose('Variables:' . '<pre>' . check_plain(var_export($variables, TRUE)) . '</pre>' + . '<hr />' . 'Result:' . '<pre>' . check_plain(var_export($output, TRUE)) . '</pre>' + . '<hr />' . 'Expected:' . '<pre>' . check_plain(var_export($expected, TRUE)) . '</pre>' + . '<hr />' . $output + ); + if (!$message) { + $message = '%callback rendered correctly.'; + } + $message = t($message, array('%callback' => 'theme_' . $callback . '()')); + $this->assertIdentical($output, $expected, $message); } } -- GitLab