Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Data Dictionary Field Widget (#4138)
- Loading branch information
1 parent
24bd853
commit 008e376
Showing
18 changed files
with
2,134 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
modules/data_dictionary_widget/css/dataDictionaryWidget.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
.table { | ||
display: table; | ||
width: auto; | ||
background-color: #eee; | ||
border: 1px solid #666666; | ||
border-spacing: 5px; /* cellspacing:poor IE support for this */ | ||
} | ||
|
||
.sticky-header { | ||
min-width: 0; | ||
} | ||
.caption { | ||
text-align: left; /* LTR */ | ||
} | ||
.thead { | ||
display: table-header-group; | ||
vertical-align: middle; | ||
border-color: inherit; | ||
} | ||
.thead .tr { | ||
border: 0; | ||
} | ||
|
||
.th { | ||
position: relative; | ||
box-sizing: border-box; | ||
height: 3rem; | ||
padding: 0.5rem 1rem; | ||
text-align: left; /* LTR */ | ||
color: #292323; | ||
background: #f3f4f9; | ||
line-height: 1.25rem; /* 20px */ | ||
} | ||
[dir="rtl"] .th { | ||
text-align: right; | ||
} | ||
.row { | ||
display: table-row; | ||
width: auto; | ||
clear: both; | ||
} | ||
.td { | ||
float: left; /* fix for buggy browsers */ | ||
display: table-column; | ||
width: 200px; | ||
background-color: #ccc; | ||
} | ||
#edit-field-json-metadata-0-identifier { | ||
background-color: #f4f4f4; | ||
color: #666; | ||
cursor: not-allowed; | ||
} |
8 changes: 8 additions & 0 deletions
8
modules/data_dictionary_widget/data_dictionary_widget.info.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
name: 'Data Dictionary Widget' | ||
description: 'Provides a field widget to generate a data-dictionary form' | ||
package: DKAN | ||
type: module | ||
core_version_requirement: ^9.4 || ^10 | ||
dependencies: | ||
- drupal:field | ||
- metastore |
5 changes: 5 additions & 0 deletions
5
modules/data_dictionary_widget/data_dictionary_widget.libraries.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
dataDictionaryWidget: | ||
version: 1.x | ||
css: | ||
theme: | ||
css/dataDictionaryWidget.css: {} |
133 changes: 133 additions & 0 deletions
133
modules/data_dictionary_widget/data_dictionary_widget.module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
<?php | ||
|
||
/** | ||
* @file | ||
* Module for creating Data Dictionary Widget. | ||
*/ | ||
|
||
use Drupal\Core\Entity\Display\EntityFormDisplayInterface; | ||
use Drupal\data_dictionary_widget\Fields\FieldOperations; | ||
use Drupal\node\NodeInterface; | ||
|
||
/** | ||
* Implements hook_theme(). | ||
*/ | ||
function data_dictionary_widget_theme($existing, $type, $theme, $path) { | ||
return [ | ||
'custom_table' => [ | ||
'variables' => [ | ||
'header' => [], | ||
'rows' => [], | ||
'attributes' => [], | ||
], | ||
'template' => 'custom-table', | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* Implements hook_entity_form_display_alter(). | ||
* | ||
* Dynamically set the widget type for the field_json_metadata field. | ||
*/ | ||
function data_dictionary_widget_entity_form_display_alter(EntityFormDisplayInterface $form_display, array $context) { | ||
if (data_dictionary_widget__data_dictionary_data_type_checker($context) === 'data-dictionary') { | ||
$form_display->setComponent('field_json_metadata', [ | ||
'type' => 'data_dictionary_widget', | ||
]); | ||
} | ||
} | ||
|
||
/** | ||
* Find entity field_data_type or schema based on the context. | ||
* | ||
* @param array $context | ||
* An associative array containing entity_type, bundle and form_mode. | ||
* | ||
* @return string | ||
* Schema/field_data_type value depending on form_mode. | ||
*/ | ||
function data_dictionary_widget__data_dictionary_data_type_checker($context) { | ||
|
||
if ($context['form_mode'] === "edit") { | ||
$node = \Drupal::routeMatch()->getParameter('node'); | ||
if ($node instanceof NodeInterface && $node->hasField('field_data_type')) { | ||
return $node->get('field_data_type')->value; | ||
} | ||
} | ||
|
||
if ($context['form_mode'] === "default") { | ||
return \Drupal::request()->query->get('schema'); | ||
} | ||
} | ||
|
||
/** | ||
* Implements hook_form_alter(). | ||
* | ||
* Setting form validation for unique identifier. | ||
* | ||
* Modifying current_fields array structure to prevent errors in element render array. | ||
* | ||
* Attaching module library to render theme changes. | ||
*/ | ||
function data_dictionary_widget_form_alter(&$form, &$form_state, $form_id) { | ||
$formObject = $form_state->getFormObject(); | ||
if ($formObject instanceof \Drupal\Core\Entity\EntityFormInterface) { | ||
$entity = $formObject->getEntity(); | ||
if (isset($form["field_json_metadata"]["widget"][0]["dictionary_fields"])) { | ||
if ($entity->getEntityTypeId() === 'node' && in_array($entity->bundle(), ['data'])) { | ||
$form['#attached']['library'][] = 'data_dictionary_widget/dataDictionaryWidget'; | ||
} | ||
} | ||
} | ||
|
||
if ($form_id == 'node_data_edit_form' || $form_id == 'node_data_form') { | ||
$form['#validate'][] = 'data_dictionary_widget_validate_unique_identifier'; | ||
$current_fields = !empty($form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_fields"]) ? $form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_fields"] : NULL; | ||
|
||
// The form element render array prefers child keys to be stored as arrays with a #value property. | ||
if ($current_fields) { | ||
foreach ($current_fields as $key => $value) { | ||
$keys = array_keys($value); | ||
$formatted_current_fields[$key] = []; | ||
|
||
foreach ($keys as $attr) { | ||
$formatted_current_fields[$key][$attr] = [ | ||
'#value' => $value[$attr] | ||
]; | ||
} | ||
} | ||
$form["field_json_metadata"]["widget"][0]["dictionary_fields"]["current_fields"] = $formatted_current_fields; | ||
} | ||
|
||
// Set the default value of the identifier field to a randomly generated uuid. | ||
$identifier_uuid = $form["field_json_metadata"]["widget"][0]["identifier"]["#default_value"] ?? NULL; | ||
if (!$identifier_uuid) { | ||
$uuid = \Drupal::service('uuid')->generate(); | ||
$form["field_json_metadata"]["widget"][0]["identifier"]['#default_value'] = $uuid; | ||
$form["field_json_metadata"]["widget"][0]["identifier"]['#description'] = t('<div class="form-item__description">This is the UUID of this Data Dictionary. To assign this data dictionary to a specific distribution use this <a href="/api/1/metastore/schemas/data-dictionary/items/' .$uuid. '" target="_blank">URL</a>.</div>'); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Checking if identifier is already used. | ||
*/ | ||
function data_dictionary_widget_validate_unique_identifier($form, &$form_state) { | ||
$op = $form_state->getFormObject()->getOperation(); | ||
$current_nid = ($op != "default") ? \Drupal::routeMatch()->getParameter('node')->id() : false; | ||
$existing_data_dictionary_nodes = FieldOperations::getDataDictionaries(); | ||
|
||
if (isset($form["field_json_metadata"]["widget"][0]["identifier"]["#value"])) { | ||
$submitted_identifier = $form["field_json_metadata"]["widget"][0]["identifier"]["#value"]; | ||
|
||
foreach ($existing_data_dictionary_nodes as $node) { | ||
if ($current_nid !== $node["nid"] && strtolower($submitted_identifier) === strtolower($node["identifier"])) { | ||
$form_state->setError($form["field_json_metadata"]["widget"][0]["identifier"], 'The identifier you entered is taken. Please choose another one.'); | ||
return $form_state; | ||
} | ||
} | ||
} | ||
|
||
return; | ||
} |
145 changes: 145 additions & 0 deletions
145
modules/data_dictionary_widget/src/Fields/FieldAddCreation.php
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,145 @@ | ||
<?php | ||
|
||
namespace Drupal\data_dictionary_widget\Fields; | ||
|
||
/** | ||
* Various operations for creating Data Dictionary Widget add fields. | ||
*/ | ||
class FieldAddCreation { | ||
|
||
/** | ||
* Create add fields for Data Dictionary Widget. | ||
*/ | ||
public static function addFields() { | ||
$add_fields['#access'] = FALSE; | ||
$add_fields['group'] = [ | ||
'#type' => 'fieldset', | ||
'#title' => t('Add new field'), | ||
'#collapsible' => TRUE, | ||
'#collapsed' => FALSE, | ||
]; | ||
|
||
$add_fields['group']['name'] = [ | ||
'#name' => 'field_json_metadata[0][dictionary_fields][field_collection][group][name]', | ||
'#type' => 'textfield', | ||
'#required' => TRUE, | ||
'#title' => 'Name', | ||
'#description' => t('Machine name of the field/column in the data table.'), | ||
]; | ||
$add_fields['group']['title'] = self::createTitle(); | ||
$add_fields['group']['type'] = self::createType(); | ||
$add_fields['group']['format'] = self::createFormat(); | ||
$add_fields['group']['format_other'] = self::createFormatOther(); | ||
$add_fields['group']['description'] = self::createDescriptionField(); | ||
$add_fields['group']['actions'] = self::createActionFields(); | ||
|
||
return $add_fields; | ||
} | ||
|
||
/** | ||
* Create Type field. | ||
*/ | ||
private static function createTitle() { | ||
return [ | ||
'#name' => 'field_json_metadata[0][dictionary_fields][field_collection][group][title]', | ||
'#type' => 'textfield', | ||
'#required' => TRUE, | ||
'#title' => 'Title', | ||
'#description' => t('A human-readable title.'), | ||
]; | ||
} | ||
|
||
/** | ||
* Create Type field. | ||
*/ | ||
private static function createType() { | ||
return [ | ||
'#name' => 'field_json_metadata[0][dictionary_fields][field_collection][group][type]', | ||
'#type' => 'select', | ||
'#required' => TRUE, | ||
'#title' => 'Data type', | ||
'#default_value' => 'string', | ||
'#op' => 'type', | ||
'#options' => [ | ||
'string' => t('String'), | ||
'date' => t('Date'), | ||
'integer' => t('Integer'), | ||
'number' => t('Number'), | ||
], | ||
'#ajax' => [ | ||
'callback' => '\Drupal\data_dictionary_widget\Fields\FieldCallbacks::updateFormatOptions', | ||
'method' => 'replace', | ||
'wrapper' => 'field-json-metadata-format', | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* Create Format field. | ||
*/ | ||
private static function createFormat() { | ||
return [ | ||
'#name' => 'field_json_metadata[0][dictionary_fields][field_collection][group][format]', | ||
'#type' => 'select', | ||
'#required' => TRUE, | ||
'#title' => 'Format', | ||
'#description' => FieldOperations::generateFormatDescription("string"), | ||
'#default_value' => 'default', | ||
'#prefix' => '<div id = field-json-metadata-format>', | ||
'#suffix' => '</div>', | ||
'#validated' => TRUE, | ||
'#options' => [ | ||
'default' => t('default'), | ||
'email' => t('email'), | ||
'uri' => t('uri'), | ||
'binary' => t('binary'), | ||
'uuid' => t('uuid'), | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* Create Format Other field. | ||
*/ | ||
private static function createFormatOther() { | ||
return [ | ||
'#name' => 'field_json_metadata[0][dictionary_fields][field_collection][group][format_other]', | ||
'#type' => 'textfield', | ||
'#title' => t('Other format'), | ||
'#description' => t('A supported format'), | ||
'#states' => [ | ||
'visible' => [ | ||
':input[name="field_json_metadata[0][dictionary_fields][field_collection][group][format]"]' => ['value' => 'other'], | ||
], | ||
'required' => [ | ||
':input[name="field_json_metadata[0][dictionary_fields][field_collection][group][format]"]' => ['value' => 'other'], | ||
], | ||
], | ||
]; | ||
} | ||
|
||
/** | ||
* Create Action buttons. | ||
*/ | ||
private static function createActionFields() { | ||
return [ | ||
'#type' => 'actions', | ||
'save_settings' => FieldButtons::submitButton('add', NULL), | ||
'cancel_settings' => FieldButtons::cancelButton('cancel', NULL), | ||
]; | ||
} | ||
|
||
/** | ||
* Create Description field. | ||
*/ | ||
private static function createDescriptionField() { | ||
return [ | ||
'#name' => 'field_json_metadata[0][dictionary_fields][field_collection][group][description]', | ||
'#type' => 'textfield', | ||
'#required' => TRUE, | ||
'#title' => 'Description', | ||
'#description' => t('Information about the field data.'), | ||
]; | ||
} | ||
|
||
} |
Oops, something went wrong.