Issue #1152216 by sun, jhedstrom: Fixed (Long) text field (textarea) with 'Default' formatter does not retain newlines.
parent
71176ec3f2
commit
6a8bb2e4d4
|
@ -38,7 +38,9 @@ class TextPlainFormatter extends FormatterBase {
|
|||
$elements = array();
|
||||
|
||||
foreach ($items as $delta => $item) {
|
||||
$elements[$delta] = array('#markup' => strip_tags($item['value']));
|
||||
// The text value has no text format assigned to it, so the user input
|
||||
// should equal the output, including newlines.
|
||||
$elements[$delta] = array('#markup' => nl2br(check_plain($item['value'])));
|
||||
}
|
||||
|
||||
return $elements;
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Contains \Drupal\text\Tests\Formatter\TextPlainUnitTest.
|
||||
*/
|
||||
|
||||
namespace Drupal\text\Tests\Formatter;
|
||||
|
||||
use Drupal\Core\Entity\EntityInterface;
|
||||
use Drupal\entity\Plugin\Core\Entity\EntityDisplay;
|
||||
use Drupal\simpletest\DrupalUnitTestBase;
|
||||
|
||||
/**
|
||||
* Tests the text_plain field formatter.
|
||||
*
|
||||
* @todo Move assertion helper methods into DrupalUnitTestBase.
|
||||
* @todo Move field helper methods, $modules, and setUp() into a new
|
||||
* FieldPluginUnitTestBase.
|
||||
*/
|
||||
class TextPlainUnitTest extends DrupalUnitTestBase {
|
||||
|
||||
/**
|
||||
* Modules to enable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $modules = array('entity', 'field', 'field_sql_storage', 'text', 'field_test');
|
||||
|
||||
/**
|
||||
* Contains rendered content.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $content;
|
||||
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'Text field text_plain formatter',
|
||||
'description' => "Test the creation of text fields.",
|
||||
'group' => 'Field types',
|
||||
);
|
||||
}
|
||||
|
||||
function setUp() {
|
||||
parent::setUp();
|
||||
|
||||
$this->installSchema('field', 'field_config');
|
||||
$this->installSchema('field', 'field_config_instance');
|
||||
|
||||
// @todo Add helper methods for all of the following.
|
||||
|
||||
$this->entity_type = 'test_entity';
|
||||
if (!isset($this->bundle)) {
|
||||
$this->bundle = $this->entity_type;
|
||||
}
|
||||
|
||||
$this->field_name = drupal_strtolower($this->randomName());
|
||||
$this->field_type = 'text_long';
|
||||
$this->field_settings = array();
|
||||
$this->instance_settings = array(
|
||||
'text_processing' => FALSE,
|
||||
);
|
||||
|
||||
$this->widget_type = 'text_textarea';
|
||||
$this->widget_settings = array();
|
||||
|
||||
$this->formatter_type = 'text_plain';
|
||||
$this->formatter_settings = array();
|
||||
|
||||
$this->field = array(
|
||||
'field_name' => $this->field_name,
|
||||
'type' => $this->field_type,
|
||||
'settings' => $this->field_settings,
|
||||
);
|
||||
$this->field = field_create_field($this->field);
|
||||
|
||||
$this->instance = array(
|
||||
'entity_type' => $this->entity_type,
|
||||
'bundle' => $this->bundle,
|
||||
'field_name' => $this->field_name,
|
||||
'label' => $this->randomName(),
|
||||
'settings' => $this->instance_settings,
|
||||
'widget' => array(
|
||||
'type' => $this->widget_type,
|
||||
'settings' => $this->widget_settings,
|
||||
),
|
||||
);
|
||||
$this->instance = field_create_instance($this->instance);
|
||||
|
||||
$this->view_mode = 'default';
|
||||
$this->display = entity_get_display($this->entity_type, $this->bundle, $this->view_mode)
|
||||
->setComponent($this->field_name, array(
|
||||
'type' => $this->formatter_type,
|
||||
'settings' => $this->formatter_settings,
|
||||
));
|
||||
$this->display->save();
|
||||
|
||||
$this->langcode = LANGUAGE_NOT_SPECIFIED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an entity of type $this->entity_type and bundle $this->bundle.
|
||||
*
|
||||
* @param array $values
|
||||
* (optional) Additional values to pass to entity_create().
|
||||
*
|
||||
* @return \Drupal\Core\Entity\EntityInterface
|
||||
* The created entity object.
|
||||
*/
|
||||
protected function createEntity($values = array()) {
|
||||
$info = entity_get_info($this->entity_type);
|
||||
$bundle_key = $info['entity_keys']['bundle'];
|
||||
$entity = entity_create($this->entity_type, $values + array(
|
||||
$bundle_key => $this->bundle,
|
||||
));
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders fields of a given entity with a given display.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity object with attached fields to render.
|
||||
* @param \Drupal\entity\Plugin\Core\Entity\EntityDisplay $display
|
||||
* The display to render the fields in.
|
||||
*/
|
||||
protected function renderEntityFields(EntityInterface $entity, EntityDisplay $display) {
|
||||
$content = field_attach_view($entity, $display);
|
||||
$this->content = drupal_render($content);
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the item of a field on an entity.
|
||||
*
|
||||
* @param \Drupal\Core\Entity\EntityInterface $entity
|
||||
* The entity object.
|
||||
* @param string $field_name
|
||||
* The name of the field.
|
||||
* @param array $item
|
||||
* The new field item to set.
|
||||
* @param int $delta
|
||||
* (optional) A specific delta to set. If omitted, all field items are
|
||||
* replaced and $item will be delta 0.
|
||||
* @param string $langcode
|
||||
* (optional) A specific langcode for which to the set the field. If
|
||||
* omitted, $this->langcode is used.
|
||||
*/
|
||||
protected function setFieldItem(EntityInterface $entity, $field_name, $item, $delta = NULL, $langcode = NULL) {
|
||||
if (!isset($langcode)) {
|
||||
$langcode = $this->langcode;
|
||||
}
|
||||
if (!isset($delta)) {
|
||||
$entity->set($field_name, array(
|
||||
$langcode => array(
|
||||
0 => $item,
|
||||
),
|
||||
));
|
||||
}
|
||||
else {
|
||||
$property = $entity->get($field_name);
|
||||
$property[$langcode][$delta] = $item;
|
||||
ksort($property[$langcode]);
|
||||
$entity->set($field_name, $property);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an assertion message string.
|
||||
*
|
||||
* Unlike format_string(),
|
||||
* - all replacement tokens are exported via var_export() and sanitized for
|
||||
* output, regardless of token type used (i.e., '@', '!', and '%' do not
|
||||
* have any special meaning).
|
||||
* - Replacement token values containing newlines are automatically wrapped
|
||||
* into a PRE element to aid in debugging test failures.
|
||||
*
|
||||
* @param string $message
|
||||
* The assertion message string containing placeholders.
|
||||
* @param array $args
|
||||
* An array of replacement token values to inject into $message.
|
||||
*
|
||||
* @return string
|
||||
* The $message with exported replacement tokens, sanitized for HTML output.
|
||||
*
|
||||
* @see check_plain()
|
||||
* @see format_string()
|
||||
*/
|
||||
protected function formatString($message, array $args) {
|
||||
array_walk($args, function (&$value) {
|
||||
// Export/dump the raw replacement token value.
|
||||
$value = var_export($value, TRUE);
|
||||
// Sanitize the value for output.
|
||||
$value = htmlspecialchars($value, ENT_QUOTES, 'UTF-8');
|
||||
// Wrap the value in a PRE element if it contains newlines.
|
||||
if (strpos($value, "\n")) {
|
||||
$value = '<pre style="white-space: pre-wrap;">' . $value . '</pre>';
|
||||
}
|
||||
});
|
||||
return strtr($message, $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the plain-text version of $this->content.
|
||||
*
|
||||
* @param string $content
|
||||
* A (HTML) string.
|
||||
*
|
||||
* @return string
|
||||
* The $content with all HTML tags stripped and all HTML entities replaced
|
||||
* with their actual characters.
|
||||
*/
|
||||
protected function getPlainTextContent($content) {
|
||||
// Strip all HTML tags.
|
||||
$content = strip_tags($content);
|
||||
// Decode all HTML entities (e.g., ' ') into characters.
|
||||
$content = html_entity_decode($content, ENT_QUOTES, 'UTF-8');
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a raw string appears in $this->content.
|
||||
*
|
||||
* @param string $value
|
||||
* The raw string to look for.
|
||||
* @param string $message
|
||||
* (optional) An assertion message. If omitted, a default message is used.
|
||||
* Available placeholders:
|
||||
* - @value: The $value.
|
||||
* - @content: The current value of $this->content.
|
||||
* @param array $args
|
||||
* (optional) Additional replacement token map to pass to formatString().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
protected function assertRaw($value, $message = NULL, $args = array()) {
|
||||
if (!isset($message)) {
|
||||
$message = 'Raw string @value found in @content';
|
||||
}
|
||||
$args += array(
|
||||
'@value' => $value,
|
||||
'@content' => $this->content,
|
||||
);
|
||||
return $this->assert(strpos($this->content, $value) !== FALSE, $this->formatString($message, $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a raw string does not appear in $this->content.
|
||||
*
|
||||
* @param string $value
|
||||
* The raw string to look for.
|
||||
* @param string $message
|
||||
* (optional) An assertion message. If omitted, a default message is used.
|
||||
* Available placeholders:
|
||||
* - @value: The $value.
|
||||
* - @content: The current value of $this->content.
|
||||
* @param array $args
|
||||
* (optional) Additional replacement token map to pass to formatString().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
protected function assertNoRaw($value, $message = NULL, $args = array()) {
|
||||
if (!isset($message)) {
|
||||
$message = 'Raw string @value not found in @content';
|
||||
}
|
||||
$args += array(
|
||||
'@value' => $value,
|
||||
'@content' => $this->content,
|
||||
);
|
||||
return $this->assert(strpos($this->content, $value) === FALSE, $this->formatString($message, $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a text string appears in the text-only version of $this->content.
|
||||
*
|
||||
* @param string $value
|
||||
* The text string to look for.
|
||||
* @param string $message
|
||||
* (optional) An assertion message. If omitted, a default message is used.
|
||||
* Available placeholders:
|
||||
* - @value: The $value.
|
||||
* - @content: The current value of $this->content.
|
||||
* @param array $args
|
||||
* (optional) Additional replacement token map to pass to formatString().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
protected function assertText($value, $message = NULL, $args = array()) {
|
||||
if (!isset($message)) {
|
||||
$message = 'Text string @value found in @content';
|
||||
}
|
||||
$content = $this->getPlainTextContent($this->content);
|
||||
$args += array(
|
||||
'@value' => $value,
|
||||
'@content' => $content,
|
||||
);
|
||||
return $this->assert(strpos($content, $value) !== FALSE, $this->formatString($message, $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a text string does not appear in the text-only version of $this->content.
|
||||
*
|
||||
* @param string $value
|
||||
* The text string to look for.
|
||||
* @param string $message
|
||||
* (optional) An assertion message. If omitted, a default message is used.
|
||||
* Available placeholders:
|
||||
* - @value: The $value.
|
||||
* - @content: The current value of $this->content.
|
||||
* @param array $args
|
||||
* (optional) Additional replacement token map to pass to formatString().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE on pass, FALSE on fail.
|
||||
*/
|
||||
protected function assertNoText($value, $message = NULL, $args = array()) {
|
||||
if (!isset($message)) {
|
||||
$message = 'Text string @value not found in @content';
|
||||
}
|
||||
$content = $this->getPlainTextContent($this->content);
|
||||
$args += array(
|
||||
'@value' => $value,
|
||||
'@content' => $content,
|
||||
);
|
||||
return $this->assert(strpos($content, $value) === FALSE, $this->formatString($message, $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests text_plain formatter output.
|
||||
*/
|
||||
function testPlainText() {
|
||||
$value = $this->randomString();
|
||||
$value .= "\n\n<strong>" . $this->randomString() . '</strong>';
|
||||
$value .= "\n\n" . $this->randomString();
|
||||
|
||||
$entity = $this->createEntity(array());
|
||||
$this->setFieldItem($entity, $this->field_name, array(
|
||||
'value' => $value,
|
||||
));
|
||||
|
||||
// Verify that all HTML is escaped and newlines are retained.
|
||||
$this->renderEntityFields($entity, $this->display);
|
||||
$this->assertText($value);
|
||||
$this->assertNoRaw($value);
|
||||
$this->assertRaw(nl2br(check_plain($value)));
|
||||
}
|
||||
|
||||
}
|
|
@ -222,7 +222,12 @@ function _text_sanitize($instance, $langcode, $item, $column) {
|
|||
if (isset($item["safe_$column"])) {
|
||||
return $item["safe_$column"];
|
||||
}
|
||||
return $instance['settings']['text_processing'] ? check_markup($item[$column], $item['format'], $langcode) : check_plain($item[$column]);
|
||||
if ($instance['settings']['text_processing']) {
|
||||
return check_markup($item[$column], $item['format'], $langcode);
|
||||
}
|
||||
// Escape all HTML and retain newlines.
|
||||
// @see \Drupal\text\Plugin\field\formatter\TextPlainFormatter
|
||||
return nl2br(check_plain($item[$column]));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue