diff --git a/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php b/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php
index 5db1e3e..42f9b429 100644
--- a/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php
+++ b/core/modules/user/src/Tests/Views/HandlerFieldUserNameTest.php
@@ -63,7 +63,7 @@ public function testUserName() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $username, 'If the user is not linked the username should be printed out for a normal user.');
+ $this->assertEqual($render, $username, 'If the user is not linked the username should be printed out for a normal user.');
}
diff --git a/core/modules/views/src/Plugin/views/field/FieldHandlerInterface.php b/core/modules/views/src/Plugin/views/field/FieldHandlerInterface.php
index 6cd22ac..494c333 100644
--- a/core/modules/views/src/Plugin/views/field/FieldHandlerInterface.php
+++ b/core/modules/views/src/Plugin/views/field/FieldHandlerInterface.php
@@ -236,8 +236,8 @@ public function isValueEmpty($value, $empty_zero, $no_skip_empty = TRUE);
* - ellipsis: Show an ellipsis (…) at the end of the trimmed string.
* - html: Make sure that the html is correct.
*
- * @return string
- * The rendered string.
+ * @return string|\Drupal\Component\Utility\SafeStringInterface
+ * The rendered output, or a SafeString object.
*/
public function renderText($alter);
diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
index ee16994..b356034 100644
--- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
+++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php
@@ -10,6 +10,7 @@
use Drupal\Component\Utility\Html;
use Drupal\Component\Utility\NestedArray;
use Drupal\Component\Utility\SafeMarkup;
+use Drupal\Component\Utility\SafeStringInterface;
use Drupal\Component\Utility\Unicode;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Component\Utility\Xss;
@@ -1138,7 +1139,7 @@ public function advancedRender(ResultRow $values) {
else {
$value = $this->render($values);
if (is_array($value)) {
- $value = (string) $this->getRenderer()->render($value);
+ $value = $this->getRenderer()->render($value);
}
$this->last_render = $value;
$this->original_value = $value;
@@ -1169,14 +1170,14 @@ public function advancedRender(ResultRow $values) {
}
if (is_array($value)) {
- $value = (string) $this->getRenderer()->render($value);
+ $value = $this->getRenderer()->render($value);
}
// This happens here so that renderAsLink can get the unaltered value of
// this field as a token rather than the altered value.
$this->last_render = $value;
}
- if (empty($this->last_render)) {
+ if (empty((string) $this->last_render)) {
if ($this->isValueEmpty($this->last_render, $this->options['empty_zero'], FALSE)) {
$alter = $this->options['alter'];
$alter['alter_text'] = 1;
@@ -1185,9 +1186,6 @@ public function advancedRender(ResultRow $values) {
$this->last_render = $this->renderText($alter);
}
}
- // @todo Fix this in https://www.drupal.org/node/2280961.
- $this->last_render = SafeMarkup::set($this->last_render);
-
return $this->last_render;
}
@@ -1196,6 +1194,10 @@ public function advancedRender(ResultRow $values) {
* {@inheritdoc}
*/
public function isValueEmpty($value, $empty_zero, $no_skip_empty = TRUE) {
+ // Convert SafeStringInterface to a string for checking.
+ if ($value instanceof SafeStringInterface) {
+ $value = (string) $value;
+ }
if (!isset($value)) {
$empty = TRUE;
}
@@ -1214,6 +1216,7 @@ public function isValueEmpty($value, $empty_zero, $no_skip_empty = TRUE) {
*/
public function renderText($alter) {
$value = $this->last_render;
+ $value_is_safe = SafeMarkup::isSafe($value);
if (!empty($alter['alter_text']) && $alter['text'] !== '') {
$tokens = $this->getRenderTokens($alter);
@@ -1230,7 +1233,7 @@ public function renderText($alter) {
// Check whether the value is empty and return nothing, so the field isn't rendered.
// First check whether the field should be hidden if the value(hide_alter_empty = TRUE) /the rewrite is empty (hide_alter_empty = FALSE).
// For numeric values you can specify whether "0"/0 should be empty.
- if ((($this->options['hide_empty'] && empty($value))
+ if ((($this->options['hide_empty'] && empty((string) $value))
|| ($alter['phase'] != static::RENDER_TEXT_PHASE_EMPTY && $no_rewrite_for_empty))
&& $this->isValueEmpty($value, $this->options['empty_zero'], FALSE)) {
return '';
@@ -1239,6 +1242,9 @@ public function renderText($alter) {
if ($alter['phase'] == static::RENDER_TEXT_PHASE_EMPTY && $no_rewrite_for_empty) {
// If we got here then $alter contains the value of "No results text"
// and so there is nothing left to do.
+ if ($value_is_safe) {
+ $value = SafeString::create($value);
+ }
return $value;
}
@@ -1275,6 +1281,12 @@ public function renderText($alter) {
if (!empty($alter['nl2br'])) {
$value = nl2br($value);
}
+
+ // Preserve whether or not the string is safe. Since $suffix comes from
+ // \Drupal::l(), it is safe to append.
+ if ($value_is_safe) {
+ $value = SafeString::create($value . $suffix);
+ }
$this->last_render_text = $value;
if (!empty($alter['make_link']) && (!empty($alter['path']) || !empty($alter['url']))) {
@@ -1284,7 +1296,16 @@ public function renderText($alter) {
$value = $this->renderAsLink($alter, $value, $tokens);
}
- return $value . $suffix;
+ // Preserve whether or not the string is safe. Since $suffix comes from
+ // \Drupal::l(), it is safe to append.
+ if ($value_is_safe) {
+ return SafeString::create($value . $suffix);
+ }
+ else {
+ // If the string is not already marked safe, it is still OK to return it
+ // because it will be sanitized by Twig.
+ return $value . $suffix;
+ }
}
/**
diff --git a/core/modules/views/src/Tests/Handler/FieldFileSizeTest.php b/core/modules/views/src/Tests/Handler/FieldFileSizeTest.php
index c2c9af5..70edf22 100644
--- a/core/modules/views/src/Tests/Handler/FieldFileSizeTest.php
+++ b/core/modules/views/src/Tests/Handler/FieldFileSizeTest.php
@@ -64,9 +64,9 @@ public function testFieldFileSize() {
// Test with the bytes option.
$view->field['age']->options['file_size_display'] = 'bytes';
$this->assertEqual($view->field['age']->advancedRender($view->result[0]), '');
- $this->assertEqual($view->field['age']->advancedRender($view->result[1]), 10);
- $this->assertEqual($view->field['age']->advancedRender($view->result[2]), 1000);
- $this->assertEqual($view->field['age']->advancedRender($view->result[3]), 10000);
+ $this->assertEqual($view->field['age']->advancedRender($view->result[1]), '10');
+ $this->assertEqual($view->field['age']->advancedRender($view->result[2]), '1000');
+ $this->assertEqual($view->field['age']->advancedRender($view->result[3]), '10000');
}
}
diff --git a/core/modules/views/src/Tests/Handler/FieldUnitTest.php b/core/modules/views/src/Tests/Handler/FieldUnitTest.php
index 85fabe3..a42110b 100644
--- a/core/modules/views/src/Tests/Handler/FieldUnitTest.php
+++ b/core/modules/views/src/Tests/Handler/FieldUnitTest.php
@@ -349,7 +349,7 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_name, 'By default, a string should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_name, 'By default, a string should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
@@ -363,14 +363,14 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, '0', 'By default, 0 should not be treated as empty.');
+ $this->assertIdentical((string) $render, '0', 'By default, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "0", 'By default, "0" should not be treated as empty.');
+ $this->assertIdentical((string) $render, "0", 'By default, "0" should not be treated as empty.');
// Test when results are not rewritten and non-zero empty values are hidden.
$view->field['name']->options['hide_alter_empty'] = TRUE;
@@ -382,7 +382,7 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_name, 'If hide_empty is checked, a string should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_name, 'If hide_empty is checked, a string should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
@@ -396,14 +396,14 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, '0', 'If hide_empty is checked, but not empty_zero, 0 should not be treated as empty.');
+ $this->assertIdentical((string) $render, '0', 'If hide_empty is checked, but not empty_zero, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "0", 'If hide_empty is checked, but not empty_zero, "0" should not be treated as empty.');
+ $this->assertIdentical((string) $render, "0", 'If hide_empty is checked, but not empty_zero, "0" should not be treated as empty.');
// Test when results are not rewritten and all empty values are hidden.
$view->field['name']->options['hide_alter_empty'] = TRUE;
@@ -437,28 +437,28 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_name, 'If the rewritten string is not empty, it should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_name, 'If the rewritten string is not empty, it should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_name, 'If the rewritten string is not empty, "" should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_name, 'If the rewritten string is not empty, "" should not be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_name, 'If the rewritten string is not empty, 0 should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_name, 'If the rewritten string is not empty, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_name, 'If the rewritten string is not empty, "0" should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_name, 'If the rewritten string is not empty, "0" should not be treated as empty.');
// Test when results are rewritten to an empty string and non-zero empty results are hidden.
$view->field['name']->options['hide_alter_empty'] = TRUE;
@@ -472,7 +472,7 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_name, 'If the rewritten string is empty, it should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_name, 'If the rewritten string is empty, it should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
@@ -486,14 +486,14 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, '0', 'If the rewritten string is empty, 0 should not be treated as empty.');
+ $this->assertIdentical((string) $render, '0', 'If the rewritten string is empty, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "0", 'If the rewritten string is empty, "0" should not be treated as empty.');
+ $this->assertIdentical((string) $render, "0", 'If the rewritten string is empty, "0" should not be treated as empty.');
// Test when results are rewritten to zero as a string and non-zero empty
// results are hidden.
@@ -508,28 +508,28 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "0", 'If the rewritten string is zero and empty_zero is not checked, the string rewritten as 0 should not be treated as empty.');
+ $this->assertIdentical((string) $render, "0", 'If the rewritten string is zero and empty_zero is not checked, the string rewritten as 0 should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "0", 'If the rewritten string is zero and empty_zero is not checked, "" rewritten as 0 should not be treated as empty.');
+ $this->assertIdentical((string) $render, "0", 'If the rewritten string is zero and empty_zero is not checked, "" rewritten as 0 should not be treated as empty.');
// Test zero as an integer.
$view->result[0]->{$column_map_reversed['name']} = 0;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "0", 'If the rewritten string is zero and empty_zero is not checked, 0 should not be treated as empty.');
+ $this->assertIdentical((string) $render, "0", 'If the rewritten string is zero and empty_zero is not checked, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "0", 'If the rewritten string is zero and empty_zero is not checked, "0" should not be treated as empty.');
+ $this->assertIdentical((string) $render, "0", 'If the rewritten string is zero and empty_zero is not checked, "0" should not be treated as empty.');
// Test when results are rewritten to a valid string and non-zero empty
// results are hidden.
@@ -544,7 +544,7 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_value, 'If the original and rewritten strings are valid, it should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_value, 'If the original and rewritten strings are valid, it should not be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
@@ -558,14 +558,14 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_value, 'If the original and rewritten strings are valid, 0 should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_value, 'If the original and rewritten strings are valid, 0 should not be treated as empty.');
// Test zero as a string.
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $random_value, 'If the original and rewritten strings are valid, "0" should not be treated as empty.');
+ $this->assertIdentical((string) $render, $random_value, 'If the original and rewritten strings are valid, "0" should not be treated as empty.');
// Test when results are rewritten to zero as a string and all empty
// original values and results are hidden.
@@ -580,7 +580,7 @@ function _testHideIfEmpty() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "", 'If the rewritten string is zero, it should be treated as empty.');
+ $this->assertIdentical((string) $render, "", 'If the rewritten string is zero, it should be treated as empty.');
// Test an empty string.
$view->result[0]->{$column_map_reversed['name']} = "";
@@ -623,20 +623,20 @@ function _testEmptyText() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $empty_text, 'If a field is empty, the empty text should be used for the output.');
+ $this->assertIdentical((string) $render, $empty_text, 'If a field is empty, the empty text should be used for the output.');
$view->result[0]->{$column_map_reversed['name']} = "0";
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, "0", 'If a field is 0 and empty_zero is not checked, the empty text should not be used for the output.');
+ $this->assertIdentical((string) $render, "0", 'If a field is 0 and empty_zero is not checked, the empty text should not be used for the output.');
$view->result[0]->{$column_map_reversed['name']} = "0";
$view->field['name']->options['empty_zero'] = TRUE;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $empty_text, 'If a field is 0 and empty_zero is checked, the empty text should be used for the output.');
+ $this->assertIdentical((string) $render, $empty_text, 'If a field is 0 and empty_zero is checked, the empty text should be used for the output.');
$view->result[0]->{$column_map_reversed['name']} = "";
$view->field['name']->options['alter']['alter_text'] = TRUE;
@@ -645,13 +645,13 @@ function _testEmptyText() {
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $alter_text, 'If a field is empty, some rewrite text exists, but hide_alter_empty is not checked, render the rewrite text.');
+ $this->assertIdentical((string) $render, $alter_text, 'If a field is empty, some rewrite text exists, but hide_alter_empty is not checked, render the rewrite text.');
$view->field['name']->options['hide_alter_empty'] = TRUE;
$render = $renderer->executeInRenderContext(new RenderContext(), function () use ($view) {
return $view->field['name']->advancedRender($view->result[0]);
});
- $this->assertIdentical($render, $empty_text, 'If a field is empty, some rewrite text exists, and hide_alter_empty is checked, use the empty text.');
+ $this->assertIdentical((string) $render, $empty_text, 'If a field is empty, some rewrite text exists, and hide_alter_empty is checked, use the empty text.');
}
/**
diff --git a/core/themes/classy/templates/form/dropbutton-wrapper.html.twig b/core/themes/classy/templates/form/dropbutton-wrapper.html.twig
index 5dccc85..f162425 100644
--- a/core/themes/classy/templates/form/dropbutton-wrapper.html.twig
+++ b/core/themes/classy/templates/form/dropbutton-wrapper.html.twig
@@ -10,7 +10,7 @@
* @see template_preprocess_dropbutton_wrapper()
*/
#}
-{% if children %}
+{% if children is not empty %}
{% spaceless %}