Skip to content
Snippets Groups Projects
Commit faca14d3 authored by Mateu Aguiló Bosch's avatar Mateu Aguiló Bosch
Browse files

Issue #3313317 by e0ipso: Leverage form elements from cl_editorial

parent 5136c1a0
No related branches found
No related tags found
1 merge request!2Issue #3313317: Leverage form elements from cl_editorial
cl_components_style_selector:
css:
component:
src/assets/css/cl-components-style-selector-widget.css: { }
......@@ -9,18 +9,31 @@ field.field_settings.cl_components_style_selector:
sequence:
type: string
label: Name of the supported feature
allowed:
type: sequence
label: Allowed modules
sequence:
type: string
label: Machine name of the allowed Fractal module
forbidden:
type: sequence
label: Forbidden modules
sequence:
type: string
label: Machine name of the forbidden Fractal module
filters:
type: mapping
mapping:
allowed:
type: sequence
label: Allowed components
sequence:
type: string
label: Machine name of the allowed component
forbidden:
type: sequence
label: Forbidden components
sequence:
type: string
label: Machine name of the forbidden component
statuses:
type: sequence
label: Supported component statuses
sequence:
type: string
types:
type: sequence
label: Supported component types
sequence:
type: string
# Default value.
field.value.cl_components_style_selector:
type: mapping
......
......@@ -2,9 +2,13 @@
namespace Drupal\cl_selector_field\Plugin\Field\FieldFormatter;
use Drupal\cl_components\ComponentPluginManager;
use Drupal\cl_components\Exception\ComponentNotFoundException;
use Drupal\cl_selector_field\Plugin\Field\FieldType\StyleSelectorItem;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\FormatterBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Plugin implementation of the 'cl_selector_field_style_selector_table' formatter.
......@@ -17,11 +21,32 @@ use Drupal\Core\Field\FormatterBase;
*/
class StyleSelectorTableFormatter extends FormatterBase {
/**
* {@inheritdoc}
*/
public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, protected readonly ComponentPluginManager $componentPluginManager) {
parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings);
}
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$component_plugin_manager = $container->get('plugin.manager.cl_component');
assert($component_plugin_manager instanceof ComponentPluginManager);
return new static($plugin_id, $plugin_definition, $configuration['field_definition'], $configuration['settings'], $configuration['label'], $configuration['view_mode'], $configuration['third_party_settings'], $component_plugin_manager);
}
/**
* {@inheritdoc}
*/
public function viewElements(FieldItemListInterface $items, $langcode) {
$header[] = '#';
$cardinality = $items->getFieldDefinition()
->getFieldStorageDefinition()
->getCardinality();
if ($cardinality > 1) {
$header[] = '#';
}
$header[] = $this->t('Component');
$header[] = $this->t('Variant');
......@@ -35,14 +60,15 @@ class StyleSelectorTableFormatter extends FormatterBase {
continue;
}
$row = [];
if ($cardinality > 1) {
$row[]['#markup'] = $delta + 1;
}
$row[]['#markup'] = $delta + 1;
if ($item->component) {
$allowed_values = $item->allowedComponentValues();
$row[]['#markup'] = $allowed_values[$item->component];
try {
$component = $this->componentPluginManager->find($item->component);
$row[]['#markup'] = $component->getMetadata()->getName();
}
else {
catch (ComponentNotFoundException $e) {
$row[]['#markup'] = '';
}
$row[]['#markup'] = $item->variant ?? '';
......
......@@ -2,10 +2,9 @@
namespace Drupal\cl_selector_field\Plugin\Field\FieldType;
use Drupal\cl_components\Component\ComponentDiscovery;
use Drupal\cl_components\Component\ComponentMetadata;
use Drupal\cl_components\Exception\ComponentNotFoundException;
use Drupal\cl_components\Plugin\Component;
use Drupal\cl_editorial\Form\ComponentFiltersFormTrait;
use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
......@@ -25,20 +24,35 @@ use Drupal\Core\TypedData\DataDefinition;
*/
class StyleSelectorItem extends FieldItemBase {
use ComponentFiltersFormTrait;
const VARIANT = 'variant';
/**
* {@inheritdoc}
*/
public static function defaultFieldSettings() {
$settings = [
$default_settings = [
'features' => [
static::VARIANT => static::VARIANT,
],
'forbidden' => [],
'allowed' => [],
'filters' => [
'forbidden' => [],
'allowed' => [],
'statuses' => [
ComponentMetadata::COMPONENT_STATUS_READY,
ComponentMetadata::COMPONENT_STATUS_BETA,
ComponentMetadata::COMPONENT_STATUS_WIP,
ComponentMetadata::COMPONENT_STATUS_DEPRECATED,
],
'types' => [
ComponentMetadata::COMPONENT_TYPE_ORGANISM,
ComponentMetadata::COMPONENT_TYPE_MOLECULE,
ComponentMetadata::COMPONENT_TYPE_ATOM,
],
],
];
return $settings + parent::defaultFieldSettings();
return $default_settings + parent::defaultFieldSettings();
}
/**
......@@ -46,8 +60,12 @@ class StyleSelectorItem extends FieldItemBase {
*/
public function fieldSettingsForm(array $form, FormStateInterface $form_state) {
$settings = $this->getSettings();
$message = $this->t('Set a combination of filters to control the list of components that will become blocks.');
$parents = ['settings'];
$form_settings = $settings['filters'];
static::buildSettingsForm($form, $form_state, cl_components_manager(), $form_settings, $parents, $message);
$element['features'] = [
$form['features'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Supported features'),
'#description' => $this->t('The component is mandatory, but the variant support is optional for each field instance.'),
......@@ -56,46 +74,27 @@ class StyleSelectorItem extends FieldItemBase {
static::VARIANT => $this->t('Variant'),
],
];
$options = $this->allAllowedComponentValues();
$element['forbidden'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Forbidden components'),
'#description' => $this->t('When showing the component dropdown, all components will be displayed except the components selected here. This is used to limit the components available for a given content type.'),
'#options' => $options,
'#default_value' => $settings['forbidden'],
'#attributes' => ['class' => ['long-checkboxes-list']],
];
$element['allowed'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Allowed components'),
'#description' => $this->t('When showing the component dropdown, only the components selected here will be displayed as an option. <strong>NOTE:</strong> "forbidden" components will not be shown even when allowed here.'),
'#options' => $options,
'#default_value' => $settings['allowed'],
'#attributes' => ['class' => ['long-checkboxes-list']],
];
$element['#attached']['library'][] = 'cl_selector_field/cl_selector_field_style_selector';
return $element;
return $form;
}
/**
* Returns all the allowed values for 'component' sub-field.
*
* @param array $allowed
* The allowed components.
* @param array $forbidden
* The forbidden components.
*
* @return array
* The list of allowed values.
* {@inheritdoc}
*/
private function allAllowedComponentValues(array $allowed = [], array $forbidden = []): array {
$options = $this->allAllowedComponentValuesSelect($allowed, $forbidden);
return array_reduce(
$options,
static fn (array $options, array $group) => [...$options, ...$group],
[]
);
public static function fieldSettingsToConfigData(array $settings) {
// Allowed anf forbidden are nested in the form due to AJAX reasons. We undo
// that here for config storage.
$clean = static fn (array $item) => array_values(array_filter($item));
$new_settings = [
'features' => $settings['features'],
'filters' => [
'statuses' => $clean($settings['filters']['statuses'] ?? []),
'types' => $clean($settings['filters']['types'] ?? []),
'allowed' => $clean($settings['filters']['refine']['allowed'] ?? []),
'forbidden' => $clean($settings['filters']['statuses']['forbidden'] ?? []),
],
];
return parent::fieldSettingsToConfigData($new_settings);
}
/**
......@@ -109,7 +108,7 @@ class StyleSelectorItem extends FieldItemBase {
* @return array
* The list of allowed values.
*/
private function allAllowedComponentValuesSelect(array $allowed = [], array $forbidden = []): array {
private function allAllowedComponents(array $allowed, array $forbidden, array $types, array $statuses): array {
$components = \Drupal::service('plugin.manager.cl_component')
->getAllComponentsWithoutDupesWithFilters(
$allowed,
......@@ -127,22 +126,14 @@ class StyleSelectorItem extends FieldItemBase {
],
FALSE
);
$options = [];
foreach ($components as $component) {
assert($component instanceof Component);
$metadata = $component->getMetadata();
$machine_name = $metadata->getMachineName();
if (!isset($options[$metadata->getGroup()])) {
$options[$metadata->getGroup()] = [];
}
$name = $component->getMetadata()->getName();
$options[$metadata->getGroup()][$machine_name] = $name;
}
ksort($options);
foreach ($options as $group => $opts) {
natsort($options[$group]);
}
return $options;
return array_reduce(
$components,
static fn(array $carry, Component $component) => [
...$carry,
$component->getId() => $component,
],
[]
);
}
/**
......@@ -170,14 +161,21 @@ class StyleSelectorItem extends FieldItemBase {
*/
public function getConstraints() {
$constraints = parent::getConstraints();
$clean = static fn (array $a) => array_values(array_filter($a));
$allowed = $clean($this->getFieldDefinition()->getSetting('allowed'));
$forbidden = $clean($this->getFieldDefinition()->getSetting('forbidden'));
$values = $this->allAllowedComponentValues($allowed, $forbidden);
$options['component']['AllowedValues'] = array_keys($values);
$options['component']['NotBlank'] = [];
$clean = static fn(array $a) => array_values(array_filter($a));
$definition = $this->getFieldDefinition();
$filters = $definition->getSetting('filters');
$allowed = $clean($filters['allowed'] ?? []);
$forbidden = $clean($filters['forbidden'] ?? []);
$types = $clean($filters['types'] ?? []);
$statuses = $clean($filters['statuses'] ?? []);
$values = $this->allAllowedComponents($allowed, $forbidden, $types, $statuses);
$options['component'] = [];
if (!empty($this->values)) {
$options['component']['AllowedValues'] = array_keys($values);
$options['component']['AllowedValues'][] = NULL;
}
$constraint_manager = \Drupal::typedDataManager()
$constraint_manager = $this->getTypedDataManager()
->getValidationConstraintManager();
$constraints[] = $constraint_manager->create('ComplexData', $options);
return $constraints;
......@@ -211,54 +209,4 @@ class StyleSelectorItem extends FieldItemBase {
];
}
/**
* Returns allowed values for 'component' sub-field.
*
* @return array
* The list of allowed values.
*/
public function allowedComponentValues(): array {
return array_reduce(
$this->allowedComponentValuesSelect(),
static function (array $options, array $group) {
return array_merge($options, $group);
},
[]
);
}
/**
* Returns allowed values for 'component' sub-field when using a select.
*
* @return array
* The list of allowed values.
*/
private function allowedComponentValuesSelect(): array {
$settings = $this->getSettings();
$allowed = array_keys(array_filter($settings['allowed'] ?? []));
$forbidden = array_keys(array_filter($settings['forbidden'] ?? []));
return $this->allAllowedComponentValuesSelect($allowed, $forbidden);
}
/**
* Allowed variants.
*
* @param $component_id string
* The component ID.
*
* @return string[]
* The variants.
*/
public function allowedVariantValues(string $component_id): array {
try {
$component = \Drupal::service(ComponentDiscovery::class)
->find($component_id);
$variants = $component->getVariants();
return array_combine($variants, $variants);
}
catch (ComponentNotFoundException $e) {
return [];
}
}
}
......@@ -2,7 +2,6 @@
namespace Drupal\cl_selector_field\Plugin\Field\FieldWidget;
use Drupal\cl_components\Component\ComponentDiscovery;
use Drupal\cl_components\ComponentPluginManager;
use Drupal\cl_components\Exception\ComponentNotFoundException;
use Drupal\cl_components\Plugin\Component;
......@@ -58,7 +57,8 @@ class StyleSelectorWidget extends WidgetBase {
$plugin_id,
$plugin_definition,
$configuration['field_definition'],
$configuration['settings'], $configuration['third_party_settings'],
$configuration['settings'],
$configuration['third_party_settings'],
$component_plugin_manager,
$container->getParameter('app.root')
);
......@@ -69,7 +69,8 @@ class StyleSelectorWidget extends WidgetBase {
*/
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {
$item = $items[$delta] ?? NULL;
$collect_variant = (bool) ($items->getSettings()['features']['variant'] ?? NULL);
$settings = $items->getSettings();
$collect_variant = (bool) ($settings['features']['variant'] ?? NULL);
$all_parents = array_merge(
$element['#field_parents'],
[$items->getName(), $delta, 'component']
......@@ -89,10 +90,13 @@ class StyleSelectorWidget extends WidgetBase {
$selected_component = NULL;
}
}
$filter_props = ['allowed', 'forbidden', 'statuses', 'types'];
$filters = array_intersect_key($settings['filters'], array_flip($filter_props));
$component_element = [
...$element,
'#type' => 'cl_component_selector',
'#default_value' => ['machine_name' => $selected_component],
'#filters' => $filters,
];
$field_name = $items->getFieldDefinition()->getName();
$wrapper_id = Html::getId(sprintf('%s-%d-form-element-wrapper', $field_name, $delta));
......@@ -122,7 +126,7 @@ class StyleSelectorWidget extends WidgetBase {
'#weight' => 5,
];
}
else{
else {
$element['component']['variant'] = ['#type' => 'hidden', '#value' => ''];
}
return [
......
#style-selector-wrapper {
border: 1px solid lightgrey;
padding: 10px;
}
#style-selector-wrapper details {
border-radius: 3px;
background-color: rgba(0, 0, 0, 0.1);
}
#style-selector-wrapper details summary {
display: block;
}
#style-selector-wrapper figure {
margin-left: 0;
margin-right: 0;
}
#style-selector-wrapper figure figcaption {
margin-top: 0.5em;
margin-bottom: 0.5em;
}
#style-selector-wrapper .component-status {
text-transform: uppercase;
display: inline-block;
border-radius: 2rem;
padding: .125rem .75rem;
color: #fff;
white-space: nowrap;
margin-left: 0.5rem;
}
#style-selector-wrapper .component-status.ready {
background-color: #24a148;
border-color: #24a148;
}
#style-selector-wrapper .component-status.ready::after {
content: "Ready";
}
#style-selector-wrapper .component-status.wip {
background-color: #f1c21b;
border-color: #f1c21b;
}
#style-selector-wrapper .component-status.wip::after {
content: "WIP";
}
#style-selector-wrapper .component-status.prototype {
background-color: #da1e28;
border-color: #da1e28;
}
#style-selector-wrapper .component-status.prototype::after {
content: "Prototype";
}
#style-selector-wrapper .component-status.design_qa {
background-color: #24a148;
border-color: #24a148;
}
#style-selector-wrapper .component-status.design_qa::after {
content: "Design QA";
}
.container-inline.cl-components-style-selector-elements .form-item {
margin: 0 3px;
}
.container-inline.cl-components-style-selector-elements .module-info .details-wrapper {
display: flex;
align-items: flex-start;
}
.container-inline.cl-components-style-selector-elements .module-info .details-wrapper img {
width: 25%;
padding-right: 1em;
}
.container-inline.cl-components-style-selector-elements label {
display: block;
}
.long-checkboxes-list .form-checkboxes {
display: flex;
flex-wrap: wrap;
}
.long-checkboxes-list .form-checkboxes .form-item {
width: 14em;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment