summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwebchick2014-02-06 20:26:52 -0800
committerwebchick2014-02-06 20:26:52 -0800
commit7a695724a3a2a53d4d7ac88abbf3b32b017ee8af (patch)
treeb614e4dccd006802c1c8d80d0e45769560767186
parent062127e7bc5197fcedab076336fa171512d3e059 (diff)
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
-rw-r--r--core/includes/form.inc50
-rw-r--r--core/includes/theme.inc1
-rw-r--r--core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php44
-rw-r--r--core/modules/system/templates/details.html.twig33
4 files changed, 87 insertions, 41 deletions
diff --git a/core/includes/form.inc b/core/includes/form.inc
index 35879a3..d0231a2 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -979,44 +979,34 @@ function theme_fieldset($variables) {
}
/**
- * Returns HTML for a details form element and its children.
+ * Prepares variables for details element templates.
*
- * @param $variables
+ * Default template: details.html.twig.
+ *
+ * @param array $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
- * Properties used: #attributes, #children, #collapsed, #description, #id,
- * #title, #value.
+ * Properties used: #attributes, #children, #collapsed, #collapsible,
+ * #description, #id, #title, #value.
*
* @ingroup themeable
*/
-function theme_details($variables) {
+function template_preprocess_details(&$variables) {
$element = $variables['element'];
- element_set_attributes($element, array('id'));
- _form_set_attributes($element, array('form-wrapper'));
-
- $output = '<details' . new Attribute($element['#attributes']) . '>';
+ $variables['attributes'] = $element['#attributes'];
+ $variables['summary_attributes'] = new Attribute();
if (!empty($element['#title'])) {
- $summary_attributes = new Attribute(array(
- 'role' => 'button',
- ));
+ $variables['summary_attributes']['role'] = 'button';
if (!empty($element['#attributes']['id'])) {
- $summary_attributes['aria-controls'] = $element['#attributes']['id'];
+ $variables['summary_attributes']['aria-controls'] = $element['#attributes']['id'];
}
- $summary_attributes['aria-expanded'] = empty($element['#attributes']['open']) ? FALSE : TRUE;
- $summary_attributes['aria-pressed'] = $summary_attributes['aria-expanded'];
- $output .= '<summary' . $summary_attributes . '>' . $element['#title'] . '</summary>';
- }
- $output .= '<div class="details-wrapper">';
- if (!empty($element['#description'])) {
- $output .= '<div class="details-description">' . $element['#description'] . '</div>';
+ $variables['summary_attributes']['aria-expanded'] = empty($element['#attributes']['open']) ? FALSE : TRUE;
+ $variables['summary_attributes']['aria-pressed'] = $variables['summary_attributes']['aria-expanded'];
}
- $output .= $element['#children'];
- if (isset($element['#value'])) {
- $output .= $element['#value'];
- }
- $output .= '</div>';
- $output .= "</details>\n";
- return $output;
+ $variables['title'] = (!empty($element['#title'])) ? $element['#title'] : '';
+ $variables['description'] = (!empty($element['#description'])) ? $element['#description'] : '';
+ $variables['children'] = (isset($element['#children'])) ? $element['#children'] : '';
+ $variables['value'] = (isset($element['#value'])) ? $element['#value'] : '';
}
/**
@@ -1980,11 +1970,11 @@ function form_process_group(&$element, &$form_state) {
* The modified element.
*/
function form_pre_render_details($element) {
+ element_set_attributes($element, array('id'));
+
// The .form-wrapper class is required for #states to treat details like
// containers.
- if (!isset($element['#attributes']['class'])) {
- $element['#attributes']['class'] = array();
- }
+ _form_set_attributes($element, array('form-wrapper'));
// Collapsible details.
$element['#attached']['library'][] = array('system', 'drupal.collapse');
diff --git a/core/includes/theme.inc b/core/includes/theme.inc
index 7065a80..bc1fbbf 100644
--- a/core/includes/theme.inc
+++ b/core/includes/theme.inc
@@ -2682,6 +2682,7 @@ function drupal_common_theme() {
),
'details' => array(
'render element' => 'element',
+ 'template' => 'details',
),
'radios' => array(
'render element' => 'element',
diff --git a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
index 750250d..a42f111 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Common/RenderTest.php
@@ -598,9 +598,6 @@ class RenderTest extends DrupalUnitTestBase {
$element = array('#cache' => $element['#cache']);
$cached_element = cache()->get(drupal_render_cid_create($element))->data;
$expected_element = array(
- '#markup' => '<details class="form-wrapper" open="open"><summary role="button" aria-expanded>Parent</summary><div class="details-wrapper"><details class="form-wrapper" open="open"><summary role="button" aria-expanded>Child</summary><div class="details-wrapper">Subchild</div></details>
-</div></details>
-',
'#attached' => array(
'js' => array(
array('type' => 'setting', 'data' => array('foo' => 'bar'))
@@ -618,7 +615,17 @@ class RenderTest extends DrupalUnitTestBase {
)
),
);
- $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.');
+
+ $dom = filter_dom_load($cached_element['#markup']);
+ $xpath = new \DOMXPath($dom);
+ $parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length;
+ $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length;
+ $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length;
+ $this->assertTrue($parent && $child && $subchild, 'The correct data is cached: the stored #markup is not affected by #post_render_cache callbacks.');
+
+ // Remove markup because it's compared above in the xpath.
+ unset($cached_element['#markup']);
+ $this->assertIdentical($cached_element, $expected_element, 'The correct data is cached: the stored #attached properties are not affected by #post_render_cache callbacks.');
// GET request: #cache enabled, cache hit.
drupal_static_reset('_drupal_add_js');
@@ -674,9 +681,6 @@ class RenderTest extends DrupalUnitTestBase {
$cached_parent_element = cache()->get(drupal_render_cid_create($element))->data;
$cached_child_element = cache()->get(drupal_render_cid_create($element['child']))->data;
$expected_parent_element = array(
- '#markup' => '<details class="form-wrapper" open="open"><summary role="button" aria-expanded>Parent</summary><div class="details-wrapper"><details class="form-wrapper" open="open"><summary role="button" aria-expanded>Child</summary><div class="details-wrapper">Subchild</div></details>
-</div></details>
-',
'#attached' => array(
'js' => array(
array('type' => 'setting', 'data' => array('foo' => 'bar'))
@@ -694,10 +698,19 @@ class RenderTest extends DrupalUnitTestBase {
)
),
);
- $this->assertIdentical($cached_parent_element, $expected_parent_element, 'The correct data is cached for the parent: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.');
+
+ $dom = filter_dom_load($cached_parent_element['#markup']);
+ $xpath = new \DOMXPath($dom);
+ $parent = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Parent"]')->length;
+ $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length;
+ $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div[@class="details-wrapper"]/details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length;
+ $this->assertTrue($parent && $child && $subchild, 'The correct data is cached for the parent: the stored #markup is not affected by #post_render_cache callbacks.');
+
+ // Remove markup because it's compared above in the xpath.
+ unset($cached_parent_element['#markup']);
+ $this->assertIdentical($cached_parent_element, $expected_parent_element, 'The correct data is cached for the parent: the stored #attached properties are not affected by #post_render_cache callbacks.');
+
$expected_child_element = array(
- '#markup' => '<details class="form-wrapper" open="open"><summary role="button" aria-expanded>Child</summary><div class="details-wrapper">Subchild</div></details>
-',
'#attached' => array(
'library' => array(
array('system', 'drupal.collapse'),
@@ -710,7 +723,16 @@ class RenderTest extends DrupalUnitTestBase {
)
),
);
- $this->assertIdentical($cached_child_element, $expected_child_element, 'The correct data is cached for the child: the stored #markup and #attached properties are not affected by #post_render_cache callbacks.');
+
+ $dom = filter_dom_load($cached_child_element['#markup']);
+ $xpath = new \DOMXPath($dom);
+ $child = $xpath->query('//details[@class="form-wrapper" and @open="open"]/summary[@role="button" and @aria-expanded and text()="Child"]')->length;
+ $subchild = $xpath->query('//details[@class="form-wrapper" and @open="open"]/div [@class="details-wrapper" and text()="Subchild"]')->length;
+ $this->assertTrue($child && $subchild, 'The correct data is cached for the child: the stored #markup is not affected by #post_render_cache callbacks.');
+
+ // Remove markup because it's compared above in the xpath.
+ unset($cached_child_element['#markup']);
+ $this->assertIdentical($cached_child_element, $expected_child_element, 'The correct data is cached for the child: the stored #attached properties are not affected by #post_render_cache callbacks.');
// GET request: #cache enabled, cache hit, parent element.
drupal_static_reset('_drupal_add_js');
diff --git a/core/modules/system/templates/details.html.twig b/core/modules/system/templates/details.html.twig
new file mode 100644
index 0000000..17ea820
--- /dev/null
+++ b/core/modules/system/templates/details.html.twig
@@ -0,0 +1,33 @@
+{#
+/**
+ * @file
+ * Default theme implementation for a details element.
+ *
+ * Available variables
+ * - attributes: A list of HTML attributes for the details element.
+ * - title: (optional) The title of the element, may not be set.
+ * - description: (optional) The description of the element, may not be set.
+ * - children: (optional) The children of the element, may not be set.
+ * - value: (optional) The value of the element, may not be set.
+ *
+ * @see template_preprocess_details()
+ *
+ * @ingroup themeable
+ */
+#}
+<details{{ attributes }}>
+ {%- if title -%}
+ <summary{{ summary_attributes }}>{{ title }}</summary>
+ {%- endif -%}
+ <div class="details-wrapper">
+ {%- if description -%}
+ <div class="details-description">{{ description }}</div>
+ {%- endif -%}
+ {%- if children -%}
+ {{ children }}
+ {%- endif -%}
+ {%- if value -%}
+ {{ value }}
+ {%- endif -%}
+ </div>
+</details>