Skip to content

Commit

Permalink
Provide text_format render element in JSON Form Widget (#4371)
Browse files Browse the repository at this point in the history
Co-authored-by: Stefan Korn <[email protected]>
  • Loading branch information
dafeder and stefan-korn authored Dec 30, 2024
1 parent fd97b42 commit cf63eea
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 12 deletions.
30 changes: 30 additions & 0 deletions modules/json_form_widget/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,36 @@ UI options:
- The text area has a height of 5 rows
- description

### Formatted Text Area

**Schema File Example:**

"description": {
"title": "Description",
"description": "Human-readable description (e.g., an abstract) with sufficient detail to enable a user to quickly understand whether the asset is of interest.",
"type": "string",
"minLength": 1
},

**UI Schema File Example:**

"description": {
"ui:options": {
"widget": "textarea",
"rows": 5,
"description": "Description (e.g., an abstract) with sufficient detail to enable a user to quickly understand whether the asset is of interest.",
"textFormat": "html"
}
},

UI options:
- textFormat: html
- This can be the machine name of any Drupal text format you have configured in your system

You can use `textFormat` to add a WYSIWYG or other Drupal text editor plugin to your dataset form. Just enable the modules you need and assign the editor to your text format in Drupal at /admin/config/content/formats.

Note that using the `textFormat` property will not affect how the field is rendered; you must handle this in your decoupled frontend or by overriding the node--data twig template or `metastore_preprocess_node__data()` method in metastore.theme.inc. See the [Theming Drupal](https://www.drupal.org/docs/develop/theming-drupal) guide for more information.

**Form Element:**

![Screenshot of a "Description" Drupal form field with a description of "Description (e.g., an abstract) with sufficient detail to enable a user to quickly understand whether the asset is of interest." used to show how a "textarea" field can be created using the JSON Form Widget module.](https://dkan-documentation-files.s3.us-east-2.amazonaws.com/dkan2/json_form_widget/string-textarea.png)
Expand Down
23 changes: 13 additions & 10 deletions modules/json_form_widget/src/ValueHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,20 @@ public function flattenValues($formValues, $property, $schema) {
* Flatten values for string properties.
*/
public function handleStringValues($formValues, $property) {
if (isset($formValues[$property]) && $formValues[$property] instanceof DrupalDateTime) {
return $formValues[$property]->format('c', ['timezone' => 'UTC']);
}
if (!empty($formValues[$property]) && isset($formValues[$property]['date_range'])) {
return $formValues[$property]['date_range'];
}
// Handle select_or_other_select.
if (isset($formValues[$property]['select'])) {
return $formValues[$property][0] ?? NULL;

if (!isset($formValues[$property])) {
return FALSE;
}
return !empty($formValues[$property]) && is_string($formValues[$property]) ? $this->cleanSelectId($formValues[$property]) : FALSE;

return match (TRUE) {
$formValues[$property] instanceof DrupalDateTime => $formValues[$property]->format('c', ['timezone' => 'UTC']),
isset($formValues[$property]['date_range']) => $formValues[$property]['date_range'],
isset($formValues[$property]['select']) => $formValues[$property][0] ?? NULL,
isset($formValues[$property]['value']) => $formValues[$property]['value'],
is_string($formValues[$property] ?? NULL) => $this->cleanSelectId($formValues[$property]),
default => FALSE,
};

}

/**
Expand Down
7 changes: 7 additions & 0 deletions modules/json_form_widget/src/WidgetRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,13 @@ public function handleUploadOrLinkElement(mixed $spec, array $element) {
public function handleTextareaElement(mixed $spec, array $element) {
$element['#type'] = 'textarea';
unset($element['#maxlength']);
if (isset($spec->textFormat)) {
$element['#type'] = 'text_format';
$element['#format'] = $spec->textFormat;
$element['#allowed_formats'] = [
$spec->textFormat,
];
}
if (isset($spec->rows)) {
$element['#rows'] = $spec->rows;
}
Expand Down
33 changes: 33 additions & 0 deletions modules/json_form_widget/tests/src/Unit/StringHelperTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
use Drupal\Component\Utility\EmailValidator;
use Drupal\Core\Form\FormState;
use Drupal\Core\StringTranslation\TranslationManager;
use Drupal\field\Plugin\migrate\source\d6\Field;
use Drupal\json_form_widget\FieldTypeRouter;
use Drupal\json_form_widget\StringHelper;
use MockChain\Options;

Expand Down Expand Up @@ -73,4 +75,35 @@ public function testEmailValidate() {
$this->assertEmpty($form_state->getErrors());
}

/**
* Test that StringHelper::handleStringElement correctly reemoves mailto:.
*/
public function testHandleStringElement() {
$definition = [
'schema' => (object) [
'title' => 'Email',
'description' => 'Email address for the contact name.',
'type' => 'string',
"pattern" => "^mailto:[\\w\\_\\~\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=\\:.-]+@[\\w.-]+\\.[\\w.-]+?$|[\\w\\_\\~\\!\\$\\&\\'\\(\\)\\*\\+\\,\\;\\=\\:.-]+@[\\w.-]+\\.[\\w.-]+?$",
],
'name' => 'hasEmail',
];

$string_helper = new StringHelper(new EmailValidator());
$field_type_router = $this->createMock(FieldTypeRouter::class);
$field_type_router->method('getSchema')->willReturn((object) [
'type' => 'object',
'properties' => [
'hasEmail' => $definition['schema'],
],
]);
$string_helper->setBuilder($field_type_router);

$data = 'mailto:[email protected]';

$result = $string_helper->handleStringElement($definition, $data);
print_r($result['#default_value']);
$this->assertEquals('[email protected]', $result['#default_value']);
}

}
49 changes: 47 additions & 2 deletions modules/json_form_widget/tests/src/Unit/ValueHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,20 @@ public function testFlattenValuesEmptyDistribution() {
$this->assertEquals([], $result);
}

/**
* Test mailto: fix.
*/
public function testFlattenValuesMailto() {
$value_handler = new ValueHandler();

$schema = json_decode('{"type":"string"}');
$formValues = [
'hasEmail' => '[email protected]',
];
$result = $value_handler->flattenValues($formValues, "hasEmail", $schema);
$this->assertEquals('mailto:[email protected]', $result);
}

/**
* Test values for datetime elements.
*/
Expand All @@ -226,7 +240,7 @@ public function testDatetimeValues() {
];
$expected = $date->format('c', ['timezone' => 'UTC']);
$result = $value_handler->handleStringValues($formValues, 'modified');
$this->assertEquals($result, $expected);
$this->assertEquals($expected, $result);

// Test date_range.
$date = new DrupalDateTime('2020-05-11T15:06:39.000Z');
Expand All @@ -240,7 +254,38 @@ public function testDatetimeValues() {
];
$expected = '2020-05-11T15:06:39.000Z/2020-05-15T15:00:00.000Z';
$result = $value_handler->handleStringValues($formValues, 'temporal');
$this->assertEquals($result, $expected);
$this->assertEquals($expected, $result);
}

/**
* Test textFormat handling.
*/
public function testTextFormat() {
$value_handler = new ValueHandler();

// Test textFormat.
$formValues = [
'description' => [
'value' => 'This is a description',
'format' => 'basic_html',
],
];
$expected = 'This is a description';
$result = $value_handler->handleStringValues($formValues, 'description');
$this->assertEquals($expected, $result);
}

public function testIntegerValues() {
$value_handler = new ValueHandler();

// Test integer.
$formValues = [
'integer' => "1",
];
$expected = 1;
$result = $value_handler->handleIntegerValues($formValues, 'integer');
$this->assertIsInt($result);
$this->assertEquals($expected, $result);
}

/**
Expand Down
17 changes: 17 additions & 0 deletions modules/json_form_widget/tests/src/Unit/WidgetRouterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,23 @@ public static function dataProvider(): array {
'#title' => 'textArea',
],
],
// A textformat property converts it to a text_format element.
'textFormat' => [
(object) [
'widget' => 'textarea',
'textFormat' => 'html',
],
[
'#type' => 'textfield',
'#title' => 'textFormat',
],
[
'#type' => 'text_format',
'#title' => 'textFormat',
'#format' => 'html',
'#allowed_formats' => ['html'],
],
],
'tagField' => [
(object) [
'widget' => 'list',
Expand Down

0 comments on commit cf63eea

Please sign in to comment.