Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide text_format render element in JSON Form Widget #4371

Merged
merged 13 commits into from
Dec 30, 2024
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:john@doe.com';

$result = $string_helper->handleStringElement($definition, $data);
print_r($result['#default_value']);
$this->assertEquals('john@doe.com', $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' => 'john@doe.com',
];
$result = $value_handler->flattenValues($formValues, "hasEmail", $schema);
$this->assertEquals('mailto:john@doe.com', $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