ds-8.x-3.9/includes/field_ui.inc
includes/field_ui.inc
<?php
/**
* @file
* Field UI functions for Display Suite.
*/
use Drupal\Core\Cache\Cache;
use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
use Drupal\Core\Entity\Entity\EntityViewDisplay;
use Drupal\Core\Form\FormState;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\Plugin\PluginFormInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Url;
use Drupal\ds\Ds;
use Drupal\ds\Plugin\DsField\DsFieldInterface;
use Drupal\field\FieldConfigInterface;
use Drupal\field_ui\FieldUI;
use Drupal\Core\StringTranslation\TranslatableMarkup;
use Drupal\Core\Link;
use Drupal\layout_builder\LayoutBuilderEnabledInterface;
/**
* Adds the Display Suite fields and layouts to the form.
*/
function ds_field_ui_fields_layouts(&$form, FormStateInterface $form_state) {
global $base_root, $base_path;
// Get the entity_type, bundle and view mode.
$entity_type = $form['#entity_type'];
$bundle = $form['#bundle'];
/* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
$entity_form = $form_state->getFormObject();
/* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $entity_display */
$entity_display = $entity_form->getEntity();
$view_mode = $entity_display->getMode();
// Check layout builder.
if ($entity_display instanceof LayoutBuilderEnabledInterface && $entity_display->isLayoutBuilderEnabled()) {
return;
}
// Create vertical tabs.
ds_field_ui_create_vertical_tabs($form);
// Add layout fieldset.
_ds_field_ui_table_layouts($entity_type, $bundle, $view_mode, $form, $form_state);
// Add/alter fields on the table, but only if a layout is selected.
if (!empty($form['#ds_layout'])) {
_ds_field_ui_fields($entity_type, $bundle, $view_mode, $form, $form_state);
// Also alter core fields.
_ds_field_ui_core_fields($form, $form_state);
}
// Special validate function for field group.
if ($form_state->has('no_field_group')) {
array_unshift($form['#validate'], '_ds_field_group_field_ui_fix_notices');
}
// Attach js.
$form['#attached']['library'][] = 'ds/admin';
// Add process function to add the regions.
$form['#process'][] = 'ds_field_ui_regions';
// Add after build function to check access of summary.
$form['#after_build'][] = 'ds_field_ui_after_build';
// Add a destination, so we can get back if layout has been changed.
$form['ds_source'] = [
'#type' => 'hidden',
'#value' => $base_root . $base_path,
];
$form['ds_destination'] = [
'#type' => 'hidden',
'#value' => \Drupal::destination()->getAsArray(),
];
$form['ds_entity_type'] = [
'#type' => 'hidden',
'#value' => $entity_type,
];
$form['ds_bundle'] = [
'#type' => 'hidden',
'#value' => $bundle,
];
$form['ds_view_mode'] = [
'#type' => 'hidden',
'#value' => $view_mode,
];
}
/**
* Create vertical tabs.
*/
function ds_field_ui_create_vertical_tabs(&$form) {
// Add additional settings vertical tab.
if (!isset($form['additional_settings'])) {
$form['additional_settings'] = [
'#type' => 'vertical_tabs',
'#theme_wrappers' => ['vertical_tabs'],
'#prefix' => '<div>',
'#suffix' => '</div>',
'#tree' => TRUE,
];
}
// @todo needs core permission
$view_mode_admin_access = \Drupal::currentUser()->hasPermission('admin_view_modes');
if (isset($form['modes'])) {
$form['modes']['#group'] = 'additional_settings';
$form['modes']['#weight'] = -10;
if ($view_mode_admin_access) {
$url = Url::fromRoute('field_ui.display_mode');
$form['modes']['view_modes_custom']['#description'] = Link::fromTextAndUrl(t('Manage display modes'), $url)->toString();
}
}
}
/**
* Add Regions to 'Manage display' screen.
*
* @param array $form
* The form to add layout fieldset and extra Display Suite fields.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The current form state.
*
* @return array
* The altered form
*/
function ds_field_ui_regions(array $form, FormStateInterface $form_state) {
// Get the entity_type, bundle and view mode.
$entity_type = $form['#entity_type'];
$bundle = $form['#bundle'];
/* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
$entity_form = $form_state->getFormObject();
/* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $entity_display */
$entity_display = $entity_form->getEntity();
$view_mode = $entity_display->getMode();
// Ignore field_group options.
if ($form_state->has('no_field_group')) {
unset($form['fields']['_add_new_group']);
$form['field_group']['#access'] = FALSE;
}
// Check layout.
$layout = $form['#ds_layout'] ?? FALSE;
// Build an array which keys are the field names and
// values are the region they are rendered in.
$field_regions = [];
// Add machine name column or not.
$add_machine_name_column_in_header = (int) Drupal::VERSION >= 11;
// Change UI to add Region column if we have a layout.
if ($layout) {
foreach ($layout['regions'] as $region_name => $field_names) {
foreach ($field_names as $field_name) {
$field_regions[$field_name] = $region_name;
}
}
$table = &$form['fields'];
$table['#header'] = [
t('Field'),
...($add_machine_name_column_in_header ? [$table['#header'][1]] : []),
t('Weight'),
t('Parent'),
t('Region'),
t('Label'),
['data' => t('Format'), 'colspan' => 3],
];
$table['#regions'] = [];
$region_options = [];
foreach ($layout['region_names'] as $region_key => $region_info) {
$region_options[$region_key] = $region_info['label'];
$table['#regions'][$region_key] = [
'title' => $region_info['label'],
'message' => t('No fields are displayed in this region'),
];
}
// Let other modules alter the regions.
$context = [
'entity_type' => $entity_type,
'bundle' => $bundle,
'view_mode' => $view_mode,
];
$region_info = [
'region_options' => &$region_options,
'table_regions' => &$table['#regions'],
];
\Drupal::moduleHandler()->alter('ds_layout_region', $context, $region_info);
$region_options['hidden'] = t('Disabled');
$table['#regions']['hidden'] = [
'title' => t('Disabled'),
'message' => t('No fields are hidden.'),
];
$region = [
'#type' => 'select',
'#options' => $region_options,
'#default_value' => 'hidden',
'#attributes' => [
'class' => ['field-region'],
],
];
// Update existing rows by changing rowHandler and adding regions.
foreach (Element::children($table) as $name) {
$row = &$table[$name];
// Don't override for field group.
if (!isset($row['#js_settings'])) {
$row['#js_settings'] = ['rowHandler' => 'field'];
}
$row['#region_callback'] = 'ds_field_ui_row_region';
// Remove hidden format.
if (isset($row['plugin']['type']['#options']['hidden'])) {
unset($row['plugin']['type']['#options']['hidden']);
}
// Add label class.
if (isset($row['label'])) {
if ($form_state->has('plugin_settings')) {
$plugin_settings = $form_state->get('plugin_settings');
if (isset($plugin_settings[$name]['ft']['settings']) && !empty($plugin_settings[$name]['ft']['settings']['lb'])) {
$row['human_name']['#plain_text'] = $plugin_settings[$name]['ft']['settings']['lb'] . ' ' . t('(Original: @orig)', ['@orig' => $row['human_name']['#plain_text']]);
}
}
}
// Add region.
// Core added regions to Field UI, which default to 'content'
if (!isset($row['region'])) {
$split = $add_machine_name_column_in_header ? 8 : 7;
$default = (isset($field_regions[$name]) && isset($region_options[$field_regions[$name]])) ? $field_regions[$name] : 'hidden';
$second = array_splice($row, $split);
$row['region'] = $region;
$row['region']['#default_value'] = $default;
$row = array_merge($row, $second);
}
else {
$region_default_value = $row['region']['#default_value'];
$default = (isset($field_regions[$name]) && isset($region_options[$field_regions[$name]])) ? $field_regions[$name] : 'hidden';
if ($region_default_value == 'content' && !isset($region_options['content'])) {
$default = key($region_options);
}
$row['region']['#options'] = $region_options;
$row['region']['#default_value'] = $default;
}
}
}
return $form;
}
/**
* Returns the region to which a row in the Field UI screen belongs.
*
* @param array $row
* The current row that is being rendered in the Field UI screen.
*
* @return string
* The region.
*/
function ds_field_ui_row_region(array $row) {
return $row['region']['#value'] ?? 'hidden';
}
/**
* After build to set the access on summary and edit button.
*
* @param $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*/
function ds_field_ui_after_build($form, FormStateInterface $form_state) {
$table = &$form['fields'];
$values = $form_state->getValue('fields');
if (!$table) {
return $form;
}
foreach (Element::children($table) as $name) {
$row = &$table[$name];
$hide_summary = FALSE;
if ($form_state->isRebuilding()) {
if (isset($values[$name]['region']) && $values[$name]['region'] == 'hidden') {
$hide_summary = TRUE;
}
}
else {
if ($row['region']['#default_value'] == 'hidden') {
$hide_summary = TRUE;
}
}
if ($hide_summary && !empty($row['settings_summary'])) {
$row['settings_summary']['#access'] = FALSE;
$row['settings_edit']['#access'] = FALSE;
}
}
return $form;
}
/**
* Validate the layout settings on the Field UI.
*/
function ds_field_ui_layouts_validate($form, FormStateInterface $form_state) {
// Determine layout variables.
$layout = $form_state->getValue('ds_layout');
if ($layout === '_none') {
$layout = '';
$form_state->setValue('ds_layout', '');
}
$old_layout = $form_state->getValue('old_layout');
$new_layout = ($layout != $old_layout) || empty($old_layout);
// Only validate the layout settings if the layout hasn't changed.
if (!$new_layout && !empty($layout)) {
/* @var \Drupal\Core\Layout\LayoutInterface $layout_plugin */
$layout_plugin = \Drupal::service('plugin.manager.core.layout')->createInstance($form_state->getValue('ds_layout'), []);
$layout_form = $form['layout_configuration'] ?? [];
foreach (Element::children($form) as $name) {
if (!empty($form[$name]['#ds_layout_configuration'])) {
$layout_form[$name] = $form[$name];
}
}
if ($layout_plugin instanceof PluginFormInterface) {
$layout_form_state = (new FormState())->setValues($form_state->getValue('layout_configuration', []));
// TODO
//$layout_plugin->validateConfigurationForm($layout_form, $layout_form_state);
}
}
// Move the view modes so Field UI can handle them.
if ($form_state->hasValue('modes')) {
$modes = $form_state->getValue('modes');
if (isset($modes['display_modes_custom'])) {
$form_state->setValue('display_modes_custom', $modes['display_modes_custom']);
}
}
}
/**
* Save the layout settings from the 'Manage display' screen.
*/
function ds_field_ui_layouts_save($form, FormStateInterface $form_state) {
$save_display = FALSE;
// Get default values.
$entity_type = $form['#entity_type'];
/* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
$entity_form = $form_state->getFormObject();
// Get the entity display.
/* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
$display = $entity_form->getEntity();
if ($display instanceof LayoutBuilderEnabledInterface && $display->isLayoutBuilderEnabled()) {
$display->unsetThirdPartySetting('ds', 'layout');
$display->unsetThirdPartySetting('ds', 'regions');
$display->unsetThirdPartySetting('ds', 'fields');
$display->save();
$form_state->set('ignore_ds_fields', FALSE);
return;
}
// Get view mode.
$view_mode = $display->getMode();
// Determine layout variables.
$layout = $form_state->getValue('ds_layout');
$disable_css = $form_state->getValue('disable_css');
$entity_classes = $form_state->getValue('entity_classes');
if (empty($entity_classes)) {
$entity_classes = 'all_classes';
}
$old_layout = $form_state->getValue('old_layout');
$new_layout = ($layout != $old_layout) || empty($old_layout);
$key = array_search('ds_field_ui_change_layout_submit', $form['actions']['submit']['#submit']);
if ($key && !empty($old_layout)) {
return;
}
$ds_layouts = Ds::getLayouts();
// Save layout and add regions if necessary.
$record = [];
$record['layout'] = [
'id' => $layout,
'library' => !empty($layout) ? $ds_layouts[$layout]->getLibrary() : FALSE,
'disable_css' => (bool) $disable_css,
'entity_classes' => $entity_classes,
];
$record['regions'] = [];
// Remove old layout if necessary.
if ($new_layout && !empty($old_layout) || empty($layout)) {
$display->unsetThirdPartySetting('ds', 'layout');
$display->unsetThirdPartySetting('ds', 'regions');
// If layout is empty, reset all fields to content, if the region is not
// set to hidden at the moment. This takes field groups into account as well
// automatically.
if (empty($layout)) {
$form_state->set('ignore_ds_fields', FALSE);
$display->unsetThirdPartySetting('ds', 'fields');
// Check for Field Group form params. If it's available, reset the
// available and default regions.
$field_group_params = $form_state->get('field_group_params');
if (isset($field_group_params) && !empty($field_group_params->available_regions) && !empty($field_group_params->default_region)) {
$field_group_params->available_regions = ['content', 'hidden'];
$field_group_params->default_region = 'hidden';
$form_state->set('field_group_params', $field_group_params);
}
$fields = $form_state->getValue('fields');
if (!empty($fields)) {
foreach (array_keys($fields) as $name) {
if (isset($fields[$name]['region'])) {
$reset_region = 'content';
if ($fields[$name]['region'] == 'hidden') {
$reset_region = 'hidden';
}
$fields[$name]['region'] = $reset_region;
}
}
}
$form_state->setValue('fields', $fields);
}
$display->save();
}
if ($new_layout && !empty($layout)) {
$save_display = TRUE;
// Move current visible fields into a default region, so
// we keep their current settings.
$layouts = Ds::getLayouts();
/** @var \Drupal\Core\Layout\LayoutDefinition $sl */
$sl = $layouts[$layout];
// TODO use default region method?
$first_region = key($sl->getRegions());
$record['layout']['settings']['classes'] = [];
$record['layout']['settings']['wrappers'] = [];
// Set default region values.
foreach ($sl->getRegions() as $region_name => $content) {
$record['layout']['settings']['wrappers'][$region_name] = 'div';
}
$record['layout']['settings']['outer_wrapper'] = 'div';
$record['layout']['settings']['attributes'] = '';
$record['layout']['settings']['link_attribute'] = FALSE;
$record['layout']['settings']['link_custom'] = '';
$fields = _ds_sort_fields((array) $form_state->getValue('fields'), 'weight');
foreach ($fields as $field_key => $field) {
// Ignore new fieldgroup, new field or existing field.
if (in_array($field_key, [
'_add_new_field',
'_add_existing_field',
'_add_new_group',
])) {
continue;
}
// Can either be form or display.
if ((isset($field['type']) && $field['type'] != 'hidden')) {
$record['regions'][$first_region][] = $field_key;
}
}
// In case this is the full node view mode and if the comment module
// is enabled for this content type, add it as well.
if ($entity_type == 'node' && $view_mode == 'full' && \Drupal::moduleHandler()->moduleExists('comment')) {
$record['regions'][$first_region][] = 'comments';
}
}
// Update existing layout.
elseif (!empty($layout)) {
$save_display = TRUE;
$fields = _ds_sort_fields((array) $form_state->getValue('fields'), 'weight');
foreach ($fields as $key => $field) {
// Make sure to hide 'hidden' fields.
if ($field['region'] == 'hidden') {
$form_state->setValue(['fields', $key, 'type'], 'hidden');
continue;
}
if (!isset($record['regions'][$field['region']])) {
$record['regions'][$field['region']] = [];
}
$record['regions'][$field['region']][] = $key;
}
/* @var \Drupal\Core\Layout\LayoutInterface $layout_plugin */
$layout_plugin = \Drupal::service('plugin.manager.core.layout')->createInstance($layout, []);
$layout_form = $form['layout_configuration'] ?? [];
foreach (Element::children($form) as $name) {
if (!empty($form[$name]['#ds_layout_configuration'])) {
$layout_form[$name] = $form[$name];
}
}
if ($layout_plugin instanceof PluginFormInterface) {
$layout_form_state = (new FormState())->setValues($form_state->getValue('layout_configuration', []));
$layout_plugin->submitConfigurationForm($layout_form, $layout_form_state);
}
// Get the layout settings from the layout_plugin.
$record['layout']['settings'] = $layout_plugin->getConfiguration();
// Let other modules alter the layout settings.
\Drupal::moduleHandler()->alter('ds_layout_settings', $record, $form_state);
}
// Save the configuration.
if ($save_display) {
// Let other modules alter the layout settings.
\Drupal::moduleHandler()->alter('ds_layout_settings', $record, $form_state);
foreach (array_keys($record) as $key) {
$display->setThirdPartySetting('ds', $key, $record[$key]);
}
$display->save();
}
}
/**
* Form validation handler for _ds_field_ui_fields().
*/
function ds_field_ui_fields_validate($form, FormStateInterface $form_state) {
$fields = $form_state->getValue('fields');
foreach (Element::children($form['fields']) as $key) {
if (isset($fields[$key]['settings_edit_form']['settings'])) {
$settings = $fields[$key]['settings_edit_form']['settings'];
if (!empty($settings)) {
$plugin_settings = $form_state->get('plugin_settings');
$plugin_settings[$key] = $settings;
$form_state->set('plugin_settings', $plugin_settings);
}
}
if (isset($fields[$key]['settings_edit_form']['third_party_settings']['ds'])) {
$settings = $fields[$key]['settings_edit_form']['third_party_settings']['ds'];
if (!empty($settings)) {
$plugin_settings = $form_state->get('plugin_settings');
$plugin_settings[$key] = $settings;
$form_state->set('plugin_settings', $plugin_settings);
}
}
}
}
/**
* Save the field settings from the 'Manage display' screen.
*/
function ds_field_ui_fields_save($form, FormStateInterface $form_state) {
if (empty($form['#ds_fields']) || $form_state->has('ignore_ds_fields')) {
return;
}
// Get the entity display.
/* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
$entity_form = $form_state->getFormObject();
/* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $display */
$display = $entity_form->getEntity();
$field_settings = [];
// Fetch values from form_state.
$all_field_values = $form_state->getValue('fields');
$all_plugin_settings = $form_state->get('plugin_settings');
// Save settings for each Display Suite field.
$ds_fields = $form['#ds_fields'];
foreach ($ds_fields as $field) {
$field_values = $all_field_values[$field];
// In case the region is hidden, do not save.
if (isset($field_values['region']) && $field_values['region'] == 'hidden') {
continue;
}
// Build settings.
$settings = [];
$settings['plugin_id'] = $field;
$settings['weight'] = $field_values['weight'];
$settings['label'] = $field_values['label'];
$settings['formatter'] = $field_values['plugin']['type'];
// Any formatter settings.
if (isset($all_plugin_settings[$field]['settings'])) {
$settings['settings'] = $all_plugin_settings[$field]['settings'];
}
elseif (isset($all_plugin_settings[$field])) {
// When the settings for that fields aren't changed the structure is
// different.
// @todo figure out how we can fix this.
$settings['settings'] = $all_plugin_settings[$field];
}
$field_settings[$field] = $settings;
// Always unset the field template settings from the regular settings array.
// @todo needs serious review.
unset($field_settings[$field]['settings']['ft']);
// Add field template plugin settings if provided.
$values = $all_plugin_settings[$field]['ft'] ?? [];
if (!empty($values)) {
$field_settings[$field]['ft'] = $values;
$default_field_function = \Drupal::config('ds.settings')->get('ft_default');
$function = $values['id'] ?? $default_field_function;
$field_settings[$field]['ft']['id'] = $function;
// It's important for schema validation to never save empty arrays.
if (empty($field_settings[$field]['ft']['settings'])) {
unset($field_settings[$field]['ft']['settings']);
}
}
// Last but not least unset the settings if they are empty after moving the
// field template settings.
if (empty($field_settings[$field]['settings'])) {
unset($field_settings[$field]['settings']);
}
}
// Save the record.
$display->unsetThirdPartySetting('ds', 'fields');
if (!empty($field_settings)) {
$display->setThirdPartySetting('ds', 'fields', $field_settings);
}
$display->save();
// Clear the ds_fields cache.
Cache::invalidateTags(['ds_fields_info']);
}
/**
* Clone a layout.
*/
function ds_field_ui_layout_clone($form, FormStateInterface $form_state) {
$clone = $form_state->getValue('clone');
[, , $cv] = explode('.', $clone);
$entity_type = $form['#entity_type'];
$bundle = $form['#bundle'];
/* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
$entity_form = $form_state->getFormObject();
// Get the entity display.
/* @var \Drupal\Core\Entity\Display\EntityDisplayInterface $old_display */
$old_display = $entity_form->getEntity();
$view_mode = $old_display->getMode();
$old_display->delete();
/* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
$display = EntityViewDisplay::load($entity_type . '.' . $bundle . '.' . $cv);
$clone_display = $display->createCopy($view_mode);
$clone_display->save();
// Show message.
\Drupal::messenger()->addMessage(t('The layout has been cloned.'));
}
/**
* Creates a summary for the field format configuration summary.
*
* @param \Drupal\ds\Plugin\DsField\DsFieldInterface $plugin_instance
* An instance of the plugin.
* @param array $settings
* The passed settings.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state of the summary.
*
* @return array
* The summary.
*/
function ds_field_settings_summary(DsFieldInterface $plugin_instance, array $settings, FormStateInterface $form_state) {
// Create the form.
$summary = $plugin_instance->settingsSummary($settings);
// Add field template summary.
ds_field_formatter_settings_summary_alter($summary, ['field_definition' => $plugin_instance, 'form_state' => $form_state]);
if (empty($summary)) {
return [];
}
return [
'#type' => 'inline_template',
'#template' => '<div class="field-plugin-summary">{{ summary|safe_join("<br />") }}</div>',
'#context' => ['summary' => $summary],
'#cell_attributes' => ['class' => ['field-plugin-summary-cell']],
];
}
/**
* Creates a form for Display Suite fields.
*
* @param \Drupal\ds\Plugin\DsField\DsFieldInterface $plugin_instance
* An instance of the plugin.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state of the form.
*
* @return mixed
* The altered form.
*/
function ds_field_settings_form(DsFieldInterface $plugin_instance, FormStateInterface $form_state) {
// Create the form.
$form = $plugin_instance->settingsForm([], $form_state);
// Add field template settings to every field if enabled.
if (\Drupal::config('ds.settings')->get('field_template')) {
$context = [
'instance' => [
'entity_type' => $plugin_instance->getEntityTypeId(),
'bundle' => $plugin_instance->bundle(),
'field_name' => $plugin_instance->getName(),
],
'view_mode' => $plugin_instance->viewMode(),
];
ds_field_template_settings_form($form, $form_state, $context);
}
return $form;
}
/**
* Add fake field group value in.
*
* @param array $form
* The actual form.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form state of the form.
*/
function _ds_field_group_field_ui_fix_notices(array $form, FormStateInterface $form_state) {
$field_group = [
'group_name' => '',
'label' => '',
];
$fields = $form_state->getValue('fields');
$fields['_add_new_group'] = $field_group;
$form_state->setValue('fields', $fields);
}
/**
* Add the layouts fieldset on the Field UI screen.
*
* @param string $entity_type
* The name of the entity type.
* @param string $bundle
* The name of the bundle.
* @param string $view_mode
* The name of the view_mode.
* @param array $form
* A collection of form properties.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The form_state.
*/
function _ds_field_ui_table_layouts($entity_type, $bundle, $view_mode, array &$form, FormStateInterface $form_state) {
$ds_layouts = Ds::getLayouts();
$layout_options = [];
unset($ds_layouts['layout_builder_blank']);
/** @var \Drupal\Core\Layout\LayoutDefinition $layout_definition */
foreach ($ds_layouts as $key => $layout_definition) {
// Create new layout option group.
$optgroup = $layout_definition->getCategory() ?: t('Other');
if ($optgroup instanceof TranslatableMarkup) {
$optgroup = (string) $optgroup;
}
if (!isset($layout_options[$optgroup])) {
$layout_options[$optgroup] = [];
}
// Stack the layout.
$layout_options[$optgroup][$key] = $layout_definition->getLabel();
}
// If there is only one $optgroup, move it to the root.
if (count($layout_options) == 1) {
$layout_options = reset($layout_options);
}
// Add layouts form.
$form['ds_layouts'] = [
'#type' => 'details',
'#title' => t('Layout for @bundle in @view_mode', [
'@bundle' => str_replace('_', ' ', $bundle),
'@view_mode' => str_replace('_', ' ', $view_mode),
]),
'#collapsible' => TRUE,
'#group' => 'additional_settings',
'#collapsed' => FALSE,
'#weight' => -100,
];
// @todo cleanup
$layout = [];
/* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
$entity_form = $form_state->getFormObject();
/* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
$display = $entity_form->getEntity();
if ($display->getThirdPartySetting('ds', 'layout')) {
$layout_configuration = $display->getThirdPartySetting('ds', 'layout');
if (isset($ds_layouts[$layout_configuration['id']])) {
$layout = (array) $ds_layouts[$layout_configuration['id']];
$layout['layout'] = $layout_configuration['id'];
$layout['disable_css'] = $layout_configuration['disable_css'] ?? FALSE;
$layout['entity_classes'] = $layout_configuration['entity_classes'] ?? 'all_classes';
$layout['settings'] = $layout_configuration['settings'] ?: [];
$layout['regions'] = $display->getThirdPartySetting('ds', 'regions');
$layout['fields'] = $display->getThirdPartySetting('ds', 'fields');
}
else {
\Drupal::messenger()->addMessage(t('The configured layout (@layout) is missing, please select a new one', ['@layout' => $layout_configuration['id']]), 'error');
}
}
if (!empty($layout) && isset($layout['layout']) && isset($ds_layouts[$layout['layout']])) {
$layout['region_names'] = $ds_layouts[$layout['layout']]->getRegions();
$form['#ds_layout'] = $layout;
}
// Load the layout preview form.
$layout['layout_options'] = $layout_options;
_ds_field_ui_table_layouts_preview($form, $form_state, $ds_layouts, $layout, $display);
if (!empty($layout['settings'])) {
/* @var \Drupal\Core\Layout\LayoutInterface $layout_plugin */
$layout_plugin = \Drupal::service('plugin.manager.core.layout')->createInstance($layout['layout'], $layout['settings'] ?: []);
if ($layout_plugin instanceof PluginFormInterface) {
$layout_configuration_form = $layout_plugin->buildConfigurationForm([], $form_state);
// Merge 'details' elements in 'additional_settings' group into the main
// form.
foreach (Element::children($layout_configuration_form) as $name) {
$element = $layout_configuration_form[$name];
if (isset($element['#type'], $element['#group']) && $element['#type'] == 'details' && $element['#group'] == 'additional_settings') {
$form[$name] = $layout_configuration_form[$name];
unset($layout_configuration_form[$name]);
$form[$name]['#ds_layout_configuration'] = TRUE;
$form[$name]['#parents'] = ['layout_configuration', $name];
$form[$name]['#tree'] = TRUE;
if ($layout['layout'] === 'ds_reset') {
$form[$name]['#access'] = FALSE;
}
}
}
// If anything is left, then we put it on it's own vertical tab.
if (!Element::isEmpty($layout_configuration_form)) {
$form['layout_configuration'] = array_merge($layout_configuration_form, [
'#group' => 'additional_settings',
'#type' => 'details',
'#title' => t('Layout settings'),
'#tree' => TRUE,
]);
}
}
}
else {
// See if we can clone from another view mode.
$options = [];
$entity_displays = \Drupal::configFactory()->listAll('core.entity_view_display.' . $entity_type . '.' . $bundle);
if (!empty($entity_displays)) {
$entity_type_info = \Drupal::entityTypeManager()->getDefinition($entity_type);
foreach ($entity_displays as $name) {
$row = \Drupal::config($name)->get();
if (empty($row) || empty($row['mode']) || empty($row['targetEntityType']) || empty($row['bundle'])) {
continue;
}
if ($row['mode'] === $view_mode) {
continue;
}
if ($row['mode'] != 'default') {
$view_mode_label = \Drupal::entityTypeManager()->getStorage('entity_view_mode')->load($entity_type . '.' . $row['mode'])->label();
}
else {
$view_mode_label = 'Default';
}
if ($row['targetEntityType'] === $entity_type && $row['bundle'] === $bundle) {
if ($entity_type_info->getBundleEntityType()) {
$bundle_info = \Drupal::entityTypeManager()->getStorage($entity_type_info->getBundleEntityType())->load($bundle);
$options[$row['id']] = $entity_type_info->getLabel() . ' > ' . $bundle_info->label() . ' > ' . $view_mode_label;
}
else {
$options[$row['id']] = $entity_type_info->getLabel() . ' > ' . $view_mode_label;
}
}
}
if (!empty($options)) {
natcasesort($options);
// Clone from another layout.
$form['ds_clone'] = [
'#type' => 'details',
'#group' => 'additional_settings',
'#title' => t('Clone layout'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
];
$form['ds_clone']['clone'] = [
'#title' => t('Select an existing layout to clone.'),
'#type' => 'select',
'#options' => $options,
'#weight' => 20,
];
$form['ds_clone']['clone_submit'] = [
'#type' => 'submit',
'#value' => t('Clone layout'),
'#submit' => ['ds_field_ui_layout_clone'],
'#weight' => 21,
];
}
}
}
$form['ds_layouts']['old_layout'] = [
'#type' => 'value',
'#value' => $layout['layout'] ?? 0,
];
// Add validate and submit handlers. Layout needs be first so
// we can reset the type key for Field API fields.
$form['#validate'][] = 'ds_field_ui_layouts_validate';
array_unshift($form['actions']['submit']['#submit'], 'ds_field_ui_fields_save');
array_unshift($form['actions']['submit']['#submit'], 'ds_field_ui_layouts_save');
}
/**
* Add the layout previews to the Field UI screen.
*
* @param array $form
* A collection of form properties.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* The state of the form.
* @param array $ds_layouts
* Collection of all the layouts.
* @param array $layout
* Current selected layout.
* @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
* The entity display object.
*/
function _ds_field_ui_table_layouts_preview(array &$form, FormStateInterface $form_state, array $ds_layouts, array $layout, EntityViewDisplayInterface $display) {
$layout_string = '';
$form['ds_layouts']['ds_layout'] = [
'#type' => 'select',
'#title' => t('Select a layout'),
'#options' => $layout['layout_options'],
'#default_value' => isset($layout['layout']) ? $layout['layout'] : NULL,
'#empty_value' => '_none',
'#weight' => -1,
'#ajax' => [
'callback' => 'ds_field_ui_table_layouts_preview_callback',
'wrapper' => 'ds_layout_wrapper',
],
];
if (!isset($layout['layout'])) {
$form['ds_layouts']['ds_layout']['#description'] = t("A layout must be selected to enable Display Suite functionality.");
}
$form['ds_layouts']['preview'] = [
'#type' => 'container',
'#prefix' => '<div id="ds_layout_wrapper">',
'#suffix' => '</div>',
'#weight' => -3,
];
if (isset($layout['layout']) || $form_state->hasValue('ds_layout')) {
$layout_string = $form_state->hasValue('ds_layout') ? $form_state->getValue('ds_layout') : $layout['layout'];
}
$chosen_layout = NULL;
$suggestions_array = [];
$selected = '';
if (!empty($layout_string)) {
if (isset($ds_layouts[$layout_string])) {
/** @var \Drupal\Core\Layout\LayoutDefinition $chosen_layout */
$chosen_layout = $ds_layouts[$layout_string];
$layout_hook = $chosen_layout->getThemeHook();
if (empty($layout_hook)) {
$layout_hook = $chosen_layout->id();
}
$selected = '<strong>' . $chosen_layout->getLabel() . '</strong>';
$selected .= '<br/>' . t('The default template can be found in %path', ['%path' => $chosen_layout->getPath() . '/' . $chosen_layout->getTemplate()]);
$suggestions_array[0] = $layout_hook . '--' . $display->getTargetEntityTypeId();
$suggestions_array[2] = $layout_hook . '--' . $display->getTargetEntityTypeId() . '-' . $display->getTargetBundle();
$suggestions_array[4] = $layout_hook . '--' . $display->getTargetEntityTypeId() . '--{id}';
if ($display->getMode() != 'default') {
$suggestions_array[1] = $layout_hook . '--' . $display->getTargetEntityTypeId() . '-' . $display->getMode();
$suggestions_array[3] = $layout_hook . '--' . $display->getTargetEntityTypeId() . '-' . $display->getTargetBundle() . '-' . $display->getMode();
}
}
ksort($suggestions_array);
// Append correct extension.
foreach ($suggestions_array as $key => $value) {
$suggestion_replace = strtr($value, '_', '-');
$suggestions_array[$key] = $suggestion_replace . '.html.twig';
}
if ($form_state->hasValue('ds_layout') || (!empty($layout) && isset($layout['regions'])) && (!empty($chosen_layout))) {
$current_layout = $form_state->hasValue('ds_layout') && (!isset($layout->layout) || $form_state->getValue('ds_layout') != $layout->layout) ? t('Current layout (after save)') : t('Current layout');
$form['ds_layouts']['preview']['title'] = [
'#markup' => '<div class="ds-layout-preview-title">' . $current_layout . '</div>',
];
$form['ds_layouts']['preview']['image'] = $chosen_layout->getIcon();
$form['ds_layouts']['preview']['image']['#prefix'] = '<div class="ds-layout-preview-image">';
$form['ds_layouts']['preview']['image']['#suffix'] = '</div>';
$form['ds_layouts']['preview']['info'] = [
'#type' => 'container',
'#attributes' => [
'class' => ['ds-layout-preview-suggestion'],
],
];
$form['ds_layouts']['preview']['info']['suggestions'] = [
'#markup' => '<p>' . $selected . '</p><p>' . t('Template suggestions') . ':' . '</p>',
];
$form['ds_layouts']['preview']['info']['suggestions_list'] = [
'#theme' => 'item_list',
'#items' => $suggestions_array,
];
if (!empty($chosen_layout->getLibrary())) {
$disable_css = FALSE;
if (isset($layout['disable_css'])) {
$disable_css = $layout['disable_css'];
}
if ($form_state->hasValue('disable_css') && $disable_css !== $form_state->getValue('disable_css')) {
$disable_css = $form_state->getValue('disable_css');
}
$form['ds_layouts']['preview']['info']['settings']['disable_css'] = array(
'#type' => 'checkbox',
'#title' => t('Disable layout CSS styles'),
'#default_value' => $disable_css,
);
}
$entity_classes = 'all_classes';
if (isset($layout['entity_classes'])) {
$entity_classes = $layout['entity_classes'];
}
if ($form_state->hasValue('entity_classes') && $entity_classes !== $form_state->getValue('entity_classes')) {
$entity_classes = $form_state->getValue('entity_classes');
}
// Default classes.
$form['ds_layouts']['preview']['info']['settings']['entity_classes'] = [
'#type' => 'select',
'#title' => t('Entity classes'),
'#options' => [
'all_classes' => t('Entity, bundle and view mode'),
'no_classes' => t('No classes'),
'old_view_mode' => t('View mode (deprecated)'),
],
'#default_value' => $entity_classes,
];
$form['ds_layouts']['preview']['clear'] = [
'#markup' => '<div class="ds-after-suggestion"></div>',
];
}
if (!isset($layout['layout']) || $layout_string != $layout['layout']) {
// Get admin path.
$route = FieldUI::getOverviewRouteInfo($display->getTargetEntityTypeId(), $display->getTargetBundle());
$route_parameters = $route->getRouteParameters();
$route_parameters['view_mode_name'] = $display->getMode();
$options = $route->getOptions();
$route_name = 'entity.entity_view_display.' . $display->getTargetEntityTypeId() . '.view_mode';
$admin_path = \Drupal::service('url_generator')->generateFromRoute($route_name, $route_parameters, $options);
$destination_url = '';
// If regions aren't set we don't have to move fields.
if (isset($layout['regions'])) {
$route_name = 'ds.change_layout';
$route_parameters = [
'entity_type' => $display->getTargetEntityTypeId(),
'bundle' => $display->getTargetBundle(),
'display_mode' => $display->getMode(),
'new_layout' => $layout_string,
];
$options = [];
$destination_url = $admin_path;
}
$form['layout_changed_url'] = [
'#type' => 'value',
'#value' => [
'route_name' => $route_name,
'route_parameters' => $route_parameters,
'destination_url' => $destination_url,
'options' => $options,
],
];
array_unshift($form['actions']['submit']['#submit'], 'ds_field_ui_change_layout_submit');
}
}
}
/**
* Ajax callback for _ds_field_ui_table_layouts_preview().
*/
function ds_field_ui_table_layouts_preview_callback($form, FormStateInterface $form_state) {
return $form['ds_layouts']['preview'];
}
/**
* Form submission handler for _ds_field_ui_table_layouts_preview().
*/
function ds_field_ui_change_layout_submit($form, FormStateInterface $form_state) {
// Remove original destination.
\Drupal::request()->query->remove('destination');
$destination = $form_state->getValue('layout_changed_url');
$redirectUrl = new Url(
$destination['route_name'],
$destination['route_parameters'],
$destination['options']
);
if (!empty($destination['destination_url'])) {
$redirectUrl->setOption('query', ['destination' => $destination['destination_url']]);
}
$form_state->setRedirectUrl($redirectUrl);
}
/**
* Add the fields to the Field UI form.
*
* @param string $entity_type
* The name of the entity type.
* @param string $bundle
* The name of the bundle.
* @param string $view_mode
* The name of the view_mode.
* @param array $form
* A collection of form properties.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* A collection of form_state properties.
*/
function _ds_field_ui_fields($entity_type, $bundle, $view_mode, array &$form, FormStateInterface $form_state) {
// Do not add the fields if there is no layout.
if (!isset($form['#ds_layout'])) {
return;
}
// Get the fields and put them on the form.
$fields = Ds::getFields($entity_type);
// Get field settings.
$field_settings = $form['#ds_layout']['fields'];
$form['#field_settings'] = $field_settings;
// Add machine name column or not.
$add_machine_name_column = (int) Drupal::VERSION >= 11;
if (empty($form['fields'])) {
// EntityDisplayFormBase doesn't add the fields table and field_ui library
// when there are no fields. Since DS needs those, we add them.
$form['#attached']['library'][] = 'field_ui/drupal.field_ui';
$form['fields'] = [
'#type' => 'field_ui_table',
'#weight' => -101,
'#header' => [
t('Field'),
...($add_machine_name_column ? [
'data' => t('Machine name'),
'class' => [RESPONSIVE_PRIORITY_MEDIUM, 'machine-name'],
] : []),
t('Weight'),
t('Parent'),
t('Region'),
t('Label'),
['data' => t('Format'), 'colspan' => 3],
],
'#regions' => [],
'#attributes' => [
'class' => ['field-ui-overview'],
'id' => 'field-display-overview',
],
'#tabledrag' => [
[
'action' => 'order',
'relationship' => 'sibling',
'group' => 'field-weight',
],
[
'action' => 'match',
'relationship' => 'parent',
'group' => 'field-parent',
'subgroup' => 'field-parent',
'source' => 'field-name',
],
[
'action' => 'match',
'relationship' => 'parent',
'group' => 'field-region',
'subgroup' => 'field-region',
'source' => 'field-name',
],
],
];
// Check for the 'There are no fields yet added. You can add new fields on
// the Manage fields page.' warning message. We really don't need it.
$warnings = \Drupal::messenger()->messagesByType(MessengerInterface::TYPE_WARNING);
if (count($warnings) == 1) {
\Drupal::messenger()->deleteByType(MessengerInterface::TYPE_WARNING);
}
// In overviews involving nested rows from contributed modules (i.e
// field_group), the 'plugin type' selects can trigger a series of changes
// in child rows. The #ajax behavior is therefore not attached directly to
// the selects, but triggered by the client-side script through a hidden
// #ajax 'Refresh' button. A hidden 'refresh_rows' input tracks the name of
// affected rows.
$form['refresh_rows'] = ['#type' => 'hidden'];
$form['refresh'] = [
'#type' => 'submit',
'#value' => t('Refresh'),
'#op' => 'refresh_table',
'#submit' => ['::multistepSubmit'],
'#ajax' => [
'callback' => '::multistepAjax',
'wrapper' => 'field-display-overview-wrapper',
'effect' => 'fade',
// The button stays hidden, so we hide the Ajax spinner too. Ad-hoc
// spinners will be added manually by the client-side script.
'progress' => 'none',
],
'#attributes' => ['class' => ['visually-hidden']],
];
}
$table = &$form['fields'];
$form['#ds_fields'] = [];
$field_label_options = [
'above' => t('Above'),
'inline' => t('Inline'),
'hidden' => t('- Hidden -'),
'visually_hidden' => t('- Visually Hidden -'),
];
\Drupal::moduleHandler()->alter('ds_label_options', $field_label_options);
/* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
$entity_form = $form_state->getFormObject();
/* @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
$display = $entity_form->getEntity();
$parent_options = [];
if (function_exists('field_group_field_ui_form_params')) {
$field_group_params = field_group_field_ui_form_params($form, $display);
foreach ($field_group_params->groups as $name => $group) {
$parent_options[$name] = $group->label;
}
$parent_options['_add_new_group'] = t('Add new group');
}
foreach ($fields as $key => $field) {
if (isset($field_settings[$key]['formatter'])) {
$field['formatter'] = $field_settings[$key]['formatter'];
}
$configuration = [
'field' => $field,
'field_name' => $key,
'entity_type' => $entity_type,
'bundle' => $bundle,
'view_mode' => $view_mode,
];
// Check if we can display this field here.
/* @var $plugin_instance DsFieldInterface */
$plugin_instance = \Drupal::service('plugin.manager.ds')->createInstance($field['plugin_id'], $configuration);
if (!$plugin_instance->isAllowed()) {
continue;
}
$form['#ds_fields'][] = $key;
// Fetch saved plugin settings.
$form_state_plugin_settings = $form_state->get('plugin_settings');
// Check on formatter settings.
$plugin_settings = [];
if (isset($form_state_plugin_settings[$key])) {
$plugin_settings = $form_state_plugin_settings[$key];
}
elseif (isset($field_settings[$key]['settings']) || isset($field_settings[$key]['ft']) || isset($field_settings[$key]['ds_limit'])) {
if (isset($field_settings[$key]['settings'])) {
$plugin_settings = $field_settings[$key]['settings'];
}
if (isset($field_settings[$key]['ft'])) {
$plugin_settings['ft'] = $field_settings[$key]['ft'];
}
if (isset($field_settings[$key]['ds_limit'])) {
$plugin_settings['ds_limit'] = $field_settings[$key]['ds_limit'];
}
$form_state_plugin_settings[$key] = $plugin_settings;
}
$plugin_instance->setConfiguration($plugin_settings);
// Save fetched plugin settings.
$form_state->set('plugin_settings', $form_state_plugin_settings);
$hidden = ['hidden' => t('- Hidden -')];
// Get the formatters from the field instance.
$formatters = $plugin_instance->formatters();
// This should be temporary. Don't want to copy stuff from the object to
// the field each ajax refresh.
if (!empty($formatters)) {
$formatters = $hidden + $formatters;
}
else {
$formatters = $hidden + ['default' => t('Default')];
}
$table[$key] = [
'#row_type' => 'field',
'#js_settings' => ['field'],
'#region_callback' => 'field_ui_display_overview_row_region',
'#attributes' => ['class' => ['draggable', 'tabledrag-leaf']],
'human_name' => [
'#plain_text' => $field['title'],
],
...($add_machine_name_column ? [
'machine_name' => [
'#markup' => $key,
'#attributes' => ['class' => ['machine-name']]]
] : []),
'weight' => [
'#type' => 'textfield',
'#default_value' => isset($field_settings[$key]['weight']) ? $field_settings[$key]['weight'] : 0,
'#size' => 3,
'#attributes' => ['class' => ['field-weight']],
],
'parent_wrapper' => [
'parent' => [
'#type' => 'select',
'#empty_value' => '',
'#options' => $parent_options,
'#default_value' => isset($field_group_params->parents[$key]) ? $field_group_params->parents[$key] : '',
'#attributes' => ['class' => ['field-parent']],
'#parents' => ['fields', $key, 'parent'],
],
'hidden_name' => [
'#type' => 'hidden',
'#default_value' => $key,
'#attributes' => ['class' => ['field-name']],
],
],
'label' => [
'#type' => 'select',
'#options' => $field_label_options,
'#default_value' => isset($field_settings[$key]['label']) ? $field_settings[$key]['label'] : 'hidden',
],
'plugin' => [
'type' => [
'#type' => 'select',
'#options' => $formatters,
'#default_value' => isset($field_settings[$key]['formatter']) ? $field_settings[$key]['formatter'] : 'hidden',
'#attributes' => ['class' => ['field-plugin-type']],
],
],
'settings_summary' => [],
'settings_edit' => [],
];
if ($form_state->get('plugin_settings_edit') == $key) {
$table[$key]['settings_summary']['#attributes']['colspan'] = 2;
$settings_form = ds_field_settings_form($plugin_instance, $form_state);
ds_field_row_form_format_construct($table, $key, $settings_form, $form_state);
}
else {
// After saving, the settings are updated here as well. First we create
// the element for the table cell.
$summary = ds_field_settings_summary($plugin_instance, $plugin_settings, $form_state);
if (!empty($summary)) {
$table[$key]['settings_summary'] = $summary;
ds_field_row_form_format_summary_construct($table, $key, $form_state);
}
}
}
}
/**
* Alter the core field on the Field UI form.
*
* @param array $form
* A collection of form properties.
* @param \Drupal\Core\Form\FormStateInterface $form_state
* A collection of form_state properties.
*/
function _ds_field_ui_core_fields(array &$form, FormStateInterface $form_state) {
$entity_type = $form['#entity_type'];
$bundle = $form['#bundle'];
/* @var \Drupal\Core\Entity\EntityFormInterface $entity_form */
$entity_form = $form_state->getFormObject();
/* @var EntityViewDisplay $entity_display */
$entity_display = $entity_form->getEntity();
// Gather type information.
$instances = \Drupal::service('entity_field.manager')->getFieldDefinitions($entity_type, $bundle);
$table = &$form['fields'];
// Get all persisted values for fields and plugin settings.
$form_state_plugin_settings = $form_state->get('plugin_settings');
// Field rows.
foreach ($instances as $key => $instance) {
if ($instance instanceof FieldConfigInterface) {
$settings = $entity_display->getComponent($key);
if (empty($settings)) {
continue;
}
if (isset($form_state_plugin_settings[$key])) {
$settings = array_merge($settings, $form_state_plugin_settings[$key]);
}
// Import field settings and merge with Field API settings.
if (!isset($form_state_plugin_settings[$key])) {
$form_state_plugin_settings[$key] = isset($settings['third_party_settings']['ds']) ? $settings['third_party_settings']['ds'] : [];
}
if ($form_state->get('plugin_settings_edit') == $key) {
$table[$key]['plugin']['settings_edit_form']['actions']['save_settings']['#validate'] = ['ds_field_ui_fields_validate'];
$table[$key]['plugin']['settings_edit_form']['actions']['cancel_settings']['#validate'] = ['ds_field_ui_fields_validate'];
}
else {
if (!empty($table[$key]['settings_summary'])) {
ds_field_row_form_format_summary_construct($table, $key, $form_state);
}
}
}
}
// Set updated plugin settings.
$form_state->set('plugin_settings', $form_state_plugin_settings);
}
/**
* Helper function for building the formatter settings.
*/
function ds_field_row_form_format_construct(&$table, $key, $settings_form, FormStateInterface $form_state) {
$build_info = $form_state->getBuildInfo();
$base_button = [
'#submit' => [
[$build_info['callback_object'], 'multistepSubmit'],
],
'#validate' => [
'ds_field_ui_fields_validate',
],
'#ajax' => [
'callback' => [$build_info['callback_object'], 'multistepAjax'],
'wrapper' => 'field-display-overview-wrapper',
'effect' => 'fade',
],
'#field_name' => $key,
];
$table[$key]['plugin']['settings_edit'] = [
'#type' => 'container',
'#attributes' => ['class' => ['field-plugin-settings-edit-form']],
'#parents' => ['fields', $key, 'settings_edit_form'],
'#weight' => -5,
// Create a settings form where hooks can pick in.
'settings' => $settings_form,
'actions' => [
'#type' => 'actions',
'save_settings' => $base_button + [
'#type' => 'submit',
'#name' => $key . '_plugin_settings_update',
'#value' => t('Update'),
'#op' => 'update',
],
'cancel_settings' => $base_button + [
'#type' => 'submit',
'#name' => $key . '_plugin_settings_cancel',
'#value' => t('Cancel'),
'#op' => 'cancel',
// Do not check errors for the 'Cancel' button.
'#limit_validation_errors' => [],
],
],
];
$table[$key]['#attributes']['class'][] = 'field-plugin-settings-editing';
$table[$key]['plugin']['type']['#attributes']['class'] = ['visually-hidden'];
}
/**
* Helper function for formatter summary settings.
*/
function ds_field_row_form_format_summary_construct(&$table, $key, FormStateInterface $form_state) {
$build_info = $form_state->getBuildInfo();
$base_button = [
'#submit' => [[$build_info['callback_object'], 'multistepSubmit']],
'#ajax' => [
'callback' => [$build_info['callback_object'], 'multistepAjax'],
'wrapper' => 'field-display-overview-wrapper',
'effect' => 'fade',
],
'#field_name' => $key,
];
// Add the configure button.
$table[$key]['settings_edit'] = $base_button + [
'#type' => 'image_button',
'#name' => $key . '_plugin_settings_edit',
'#src' => 'core/misc/icons/787878/cog.svg',
'#attributes' => ['class' => ['field-plugin-settings-edit'], 'alt' => t('Edit')],
'#op' => 'edit',
// Do not check errors for the 'Edit' button, but make sure we get
// the value of the 'plugin type' select.
'#limit_validation_errors' => [['fields', $key, 'type']],
'#prefix' => '<div class="field-plugin-settings-edit-wrapper">',
'#suffix' => '</div>',
];
}
/**
* Utility function to sort a multidimensional array by a value in a sub-array.
*
* @param array $a
* The array to sort.
* @param string $subkey
* The subkey to sort by.
*
* @return array
* The sorted array.
*/
function _ds_sort_fields(array $a, $subkey) {
$c = [];
$b = [];
foreach ($a as $k => $v) {
if (isset($v[$subkey])) {
$b[$k] = $v[$subkey];
}
}
asort($b);
foreach ($b as $key => $val) {
$c[$key] = $a[$key];
}
return $c;
}
