diff --git a/core/modules/taxonomy/src/Tests/Views/TaxonomyFieldAllTermsTest.php b/core/modules/taxonomy/src/Tests/Views/TaxonomyFieldAllTermsTest.php index 8329d04..a78144f 100644 --- a/core/modules/taxonomy/src/Tests/Views/TaxonomyFieldAllTermsTest.php +++ b/core/modules/taxonomy/src/Tests/Views/TaxonomyFieldAllTermsTest.php @@ -22,7 +22,23 @@ class TaxonomyFieldAllTermsTest extends TaxonomyTestBase { * * @var array */ - public static $testViews = array('taxonomy_all_terms_test'); + public static $testViews = array('taxonomy_all_terms_test', 'test_page_display'); + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('views', 'theme_test'); + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->enableViewsTestModule(); + } /** * Tests the "all terms" field handler. @@ -43,6 +59,27 @@ public function testViewsHandlerAllTermsField() { $this->assertEqual($actual[1]->__toString(), $this->term2->label()); } + public function testViewsHandlerAllTermsFieldWithTemplate() { + // Install theme to test with template system. + \Drupal::service('theme_handler')->install(array('views_test_theme')); + + // Make base theme default then test for hook invocations. + $this->config('system.theme') + ->set('default', 'views_test_theme') + ->save(); + $this->assertEqual($this->config('system.theme')->get('default'), 'views_test_theme'); + $this->drupalGet('test_page_display_200'); + + // Assert that we are using the correct template. + $this->assertText('llama', 'Loaded the correct views-view-field.html.twig template'); + + // @todo Fix this. + $this->testViewsHandlerAllTermsField(); + + // Assert that there are no escaped '<'s characters. + $this->assertNoEscaped('<'); + } + /** * Tests token replacement in the "all terms" field handler. */ @@ -64,7 +101,7 @@ public function testViewsHandlerAllTermsWithTokens() { // The name for the vocabulary the term belongs to: {{ term_node_tid__vocabulary }} $vocabulary = Vocabulary::load($this->term1->bundle()); - $this->assertText('The name for the vocabulary the term belongs to: ' . $vocabulary->label()); + $this->assertText('The name for the vocabulary the term belongs to: ' . $vocabulary->label()); } } diff --git a/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php b/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php index 0072d67..acd3ed2 100644 --- a/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php +++ b/core/modules/user/src/Tests/Views/HandlerFieldRoleTest.php @@ -18,12 +18,24 @@ */ class HandlerFieldRoleTest extends UserTestBase { + public static $modules = array('views', 'theme_test'); + /** * Views used by this test. * * @var array */ - public static $testViews = array('test_views_handler_field_role'); + public static $testViews = array('test_views_handler_field_role', 'test_page_display'); + + + /** + * {@inheritdoc} + */ + protected function setUp() { + parent::setUp(); + + $this->enableViewsTestModule(); + } public function testRole() { // Create a couple of roles for the view. @@ -42,8 +54,6 @@ public function testRole() { $user->addRole($rolename_b); $user->save(); - debug(db_query('SELECT * FROM {user__roles}')->fetchAll()); - $view = Views::getView('test_views_handler_field_role'); $this->executeView($view); // The role field is populated during preRender. @@ -54,4 +64,28 @@ public function testRole() { $this->assertFalse(strpos($render, $rolename_not_assigned), 'View test_views_handler_field_role does not render a role not assigned to a user.'); } + /** + * Tests Role fields with + */ + public function testRoleWithTemplate() { + // Install theme to test with template system. + \Drupal::service('theme_handler')->install(array('views_test_theme')); + + // Make base theme default then test for hook invocations. + $this->config('system.theme') + ->set('default', 'views_test_theme') + ->save(); + $this->assertEqual($this->config('system.theme')->get('default'), 'views_test_theme'); + $this->drupalGet('test_page_display_200'); + + // Assert that we are using the correct template. + $this->assertText('llama', 'Loaded the correct views-view-field.html.twig template'); + + // @todo Fix this. + $this->testRole(); + + // Assert that there are no escaped '<'s characters. + $this->assertNoEscaped('<'); + } + } diff --git a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php index 152d4e9..5767789 100644 --- a/core/modules/views/src/Plugin/views/field/FieldPluginBase.php +++ b/core/modules/views/src/Plugin/views/field/FieldPluginBase.php @@ -1306,7 +1306,7 @@ public function renderText($alter) { // Preserve whether or not the string is safe. Since $suffix comes from // \Drupal::l(), it is safe to append. - if ($value_is_safe) { + if ($value_is_safe || $value instanceof SafeStringInterface) { return ViewsRenderPipelineSafeString::create($value . $suffix); } else { @@ -1544,7 +1544,9 @@ protected function renderAsLink($alter, $text, $tokens) { $value .= Xss::filterAdmin($this->viewsTokenReplace($alter['suffix'], $tokens)); } - return $value; + // Preserve whether or not the string is safe. Since 'prefix' and 'suffix' + // comes are Xss admin filtered and \Drupal::l(), it is safe to append. + return ViewsRenderPipelineSafeString::create($value); } /** diff --git a/core/modules/views/src/Plugin/views/field/PrerenderList.php b/core/modules/views/src/Plugin/views/field/PrerenderList.php index ce0caee..ee31404 100644 --- a/core/modules/views/src/Plugin/views/field/PrerenderList.php +++ b/core/modules/views/src/Plugin/views/field/PrerenderList.php @@ -7,6 +7,7 @@ namespace Drupal\views\Plugin\views\field; +use Drupal\Component\Utility\Xss; use Drupal\Core\Form\FormStateInterface; use Drupal\views\ResultRow; @@ -78,17 +79,23 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) { public function renderItems($items) { if (!empty($items)) { if ($this->options['type'] == 'separator') { - return implode($this->sanitizeValue($this->options['separator'], 'xss_admin'), $items); + $separator = Xss::filterAdmin($this->options['separator']); + $build = [ + '#type' => 'inline_template', + '#template' => '{{ items | safe_join(separator) }}', + '#context' => ['separator' => $separator, 'items' => $items], + ]; } else { - $item_list = array( + $build = array( '#theme' => 'item_list', '#items' => $items, '#title' => NULL, '#list_type' => $this->options['type'], ); - return drupal_render($item_list); } + + return \Drupal::service('renderer')->renderPlain($build); } } diff --git a/core/modules/views/src/Tests/ViewsEscapingTest.php b/core/modules/views/src/Tests/ViewsEscapingTest.php index 18e4acc..63f750a 100644 --- a/core/modules/views/src/Tests/ViewsEscapingTest.php +++ b/core/modules/views/src/Tests/ViewsEscapingTest.php @@ -69,4 +69,34 @@ public function testViewsViewFieldsEscaping() { $this->assertNoEscaped('<'); } + /** + * Tests for incorrectly escaped markup in the views-view-field.html.twig. + */ + public function testViewsViewFieldEscaping() { + // Test with system theme using theme function. + $this->drupalGet('test_page_display_200'); + + // Assert that we are using the theme function. + $this->assertNoText('llama', 'Loaded the correct theme function views_view_field()'); + + // Assert that there are no escaped '<'s characters. + $this->assertNoEscaped('<'); + + // Install theme to test with template system. + \Drupal::service('theme_handler')->install(array('views_test_theme')); + + // Make base theme default then test for hook invocations. + $this->config('system.theme') + ->set('default', 'views_test_theme') + ->save(); + $this->assertEqual($this->config('system.theme')->get('default'), 'views_test_theme'); + $this->drupalGet('test_page_display_200'); + + // Assert that we are using the correct template. + $this->assertText('llama', 'Loaded the correct views-view-field.html.twig template'); + + // Assert that there are no escaped '<'s characters. + $this->assertNoEscaped('<'); + } + } diff --git a/core/modules/views/tests/themes/views_test_theme/templates/views-view-field.html.twig b/core/modules/views/tests/themes/views_test_theme/templates/views-view-field.html.twig new file mode 100644 index 0000000..682d4db --- /dev/null +++ b/core/modules/views/tests/themes/views_test_theme/templates/views-view-field.html.twig @@ -0,0 +1,11 @@ +{# +/** + * @file + * Theme override to display all the fields in a views row. + * + * The reason for this template is to override the theme function provided by + * views. + */ +#} +{% include '@views/views-view-field.html.twig' %} +Use posts instead of twigs to protect your llamas from escaping the field. diff --git a/core/modules/views_ui/src/Tests/CustomBooleanTest.php b/core/modules/views_ui/src/Tests/CustomBooleanTest.php index 08fbda8..4e3a608 100644 --- a/core/modules/views_ui/src/Tests/CustomBooleanTest.php +++ b/core/modules/views_ui/src/Tests/CustomBooleanTest.php @@ -22,7 +22,7 @@ class CustomBooleanTest extends UITestBase { * * @var array */ - public static $testViews = array('test_view'); + public static $testViews = array('test_view', 'test_page_display'); /** * \Drupal\views\Tests\ViewTestBase::viewsData(). @@ -108,5 +108,28 @@ public function testCustomOption() { } } -} + /** + * Tests the setting and output of custom labels for boolean values. + */ + public function testCustomOptionWithTemplate() { + // Install theme to test with template system. + \Drupal::service('theme_handler')->install(array('views_test_theme')); + + // Make base theme default then test for hook invocations. + $this->config('system.theme') + ->set('default', 'views_test_theme') + ->save(); + $this->assertEqual($this->config('system.theme')->get('default'), 'views_test_theme'); + $this->drupalGet('test_page_display_200'); + // Assert that we are using the correct template. + $this->assertText('llama', 'Loaded the correct views-view-field.html.twig template'); + + // @todo Fix this. + $this->testCustomOption(); + + // Assert that there are no escaped '<'s characters. + $this->assertNoEscaped('<'); + } + +}