From 2b31bcbd5267a1f19e4334d3daa6d90657f33156 Mon Sep 17 00:00:00 2001 From: just_like_good_vibes <mickael@meulle.com> Date: Fri, 4 Apr 2025 13:04:41 +0200 Subject: [PATCH 1/5] fixed --- src/Element/ComponentFormBase.php | 37 +++++++++++++++--- src/Element/ComponentPropForm.php | 39 ++++++++----------- src/Element/ComponentSlotForm.php | 16 ++++++-- .../Source/DerivableContextSourceBase.php | 1 + 4 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/Element/ComponentFormBase.php b/src/Element/ComponentFormBase.php index 7e4fa5de..c2fed887 100644 --- a/src/Element/ComponentFormBase.php +++ b/src/Element/ComponentFormBase.php @@ -187,8 +187,8 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb /** * Get source plugin form. */ - protected static function getSourcePluginForm(FormStateInterface $form_state, SourceInterface $source, string $wrapper_id): array { - $form = $source->settingsForm([], $form_state); + protected static function getSourcePluginForm(FormStateInterface $form_state, ?SourceInterface $source, string $wrapper_id): array { + $form = $source ? $source->settingsForm([], $form_state) : []; $form["#type"] = 'container'; $form['#attributes'] = [ 'id' => $wrapper_id, @@ -214,13 +214,17 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb /** * Get selected source plugin. */ - protected static function getSelectedSource(array $configuration, array $sources): ?SourceInterface { + protected static function getSelectedSource(array $configuration, array $sources, bool $auto_select = FALSE): ?SourceInterface { $source_id = $configuration['source_id'] ?? NULL; foreach ($sources as $source) { if ($source->getPluginId() === $source_id) { return $source; } } + if ($auto_select && count($sources) > 0) { + // Default source is in first position. + return current($sources); + } return NULL; } @@ -244,6 +248,28 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb return $element; } + /** + * Add title and description to the source element. + * + * @param array $element + * The element. + * + * @return array + * The element with title and description. + */ + protected static function addTitleAndDescription(array $element): array { + if (isset($element["source"]["value"])) { + $element["source"]["value"]["#title_display"] = 'before'; + if (empty($element["source"]["value"]["#title"])) { + $element["source"]["value"]["#title"] = $element["#title"]; + } + if (empty($element["source"]["value"]["#description"])) { + $element["source"]["value"]["#description"] = $element['#description'] ?? NULL; + } + } + return $element; + } + /** * Alter the element after the form is built. * @@ -299,11 +325,11 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb /** * Build sources selector widget. */ - protected static function buildSourceSelector(array $sources, ?SourceInterface $selected_source, string $wrapper_id): array { + protected static function buildSourceSelector(array $sources, ?SourceInterface $selected_source, string $wrapper_id, bool $auto_select = TRUE): array { if (empty($sources)) { return []; } - if (count($sources) == 1) { + if ($auto_select && (count($sources) == 1)) { return [ '#type' => 'hidden', '#value' => array_keys($sources)[0], @@ -318,6 +344,7 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb '#attributes' => [ 'class' => ["uip-source-selector"], ], + '#empty_option' => t('- Select -'), // '#prop_id' => $selected_source?->getPropId(), // '#prop_definition' => $selected_source?->getPropDefinition(), '#ajax' => [ diff --git a/src/Element/ComponentPropForm.php b/src/Element/ComponentPropForm.php index 4665483c..5463c524 100644 --- a/src/Element/ComponentPropForm.php +++ b/src/Element/ComponentPropForm.php @@ -54,6 +54,7 @@ class ComponentPropForm extends ComponentFormBase { // Wrapped (into details/summary) or not. '#wrap' => FALSE, '#render_sources' => TRUE, + '#auto_select' => TRUE, '#process' => [ [$class, 'buildForm'], [$class, 'processPropOrSlot'], @@ -76,32 +77,30 @@ class ComponentPropForm extends ComponentFormBase { */ public static function buildForm(array &$element, FormStateInterface $form_state): array { $element['#tree'] = TRUE; - $prop_id = $element['#prop_id']; $component = static::getComponent($element); - if (!$component) { + if (!$component || !isset($element['#prop_id'])) { return []; } + $prop_id = $element['#prop_id']; $definition = $component->metadata->schema['properties'][$prop_id]; $configuration = $element['#default_value'] ?? []; - $sources = static::getSources($prop_id, $definition, $element); - $selected_source = static::getSelectedSource($configuration, $sources); - if (!$selected_source) { - // Default source is in first position. - $selected_source = current($sources); - } - if (!$selected_source) { - return []; - } - $wrapper_id = static::getElementId($element, 'ui-patterns-prop-item-' . $prop_id); - $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id); - $source_form = static::getSourcePluginForm($form_state, $selected_source, $wrapper_id); + // ----- + $sources = static::getSources($prop_id, $definition, $element); + $selected_source = static::getSelectedSource($configuration, $sources, $element['#auto_select'] ?? TRUE); + $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id, $element['#auto_select'] ?? TRUE); + $source_form = $selected_source ? static::getSourcePluginForm($form_state, $selected_source, $wrapper_id) : [ + '#type' => 'container', + '#attributes' => [ + 'id' => $wrapper_id, + ], + ]; $element += [ 'source_id' => $source_selector, 'source' => array_merge($source_form, ['#prop_id' => $prop_id]), ]; - if (!($element['#render_sources'] ?? TRUE)) { + if (!($element['#render_sources'] ?? TRUE) && $selected_source) { $element['source_id'] = [ '#type' => 'hidden', '#value' => $selected_source->getPluginId(), @@ -109,14 +108,8 @@ class ComponentPropForm extends ComponentFormBase { } $element = static::addRequired($element, $prop_id); // This allows "widgets" to have a title when #wrap is unset. - if (!($element['#wrap'] ?? TRUE) && isset($element["source"]["value"])) { - $element["source"]["value"]["#title_display"] = 'before'; - if (empty($element["source"]["value"]["#title"])) { - $element["source"]["value"]["#title"] = $element["#title"]; - } - if (empty($element["source"]["value"]["#description"])) { - $element["source"]["value"]["#description"] = $element['#description'] ?? NULL; - } + if (!($element['#wrap'] ?? TRUE)) { + $element = static::addTitleAndDescription($element); } return $element; } diff --git a/src/Element/ComponentSlotForm.php b/src/Element/ComponentSlotForm.php index e19fc354..f811653f 100644 --- a/src/Element/ComponentSlotForm.php +++ b/src/Element/ComponentSlotForm.php @@ -72,6 +72,7 @@ class ComponentSlotForm extends ComponentFormBase { '#display_weight' => TRUE, '#component_id' => NULL, '#slot_id' => NULL, + '#auto_select' => TRUE, '#cardinality_multiple' => TRUE, '#process' => [ [$class, 'buildForm'], @@ -278,10 +279,10 @@ class ComponentSlotForm extends ComponentFormBase { if (!isset($element['#default_value'])) { $element['#default_value'] = $configuration; } - $sources = static::getSources($slot_id, $definition, $element); - $selected_source = static::getSelectedSource($configuration, $sources); $wrapper_id = static::getElementId($element, 'ui-patterns-slot-item-' . $slot_id); - $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id); + $sources = static::getSources($slot_id, $definition, $element); + $selected_source = static::getSelectedSource($configuration, $sources, $element['#auto_select'] ?? TRUE); + $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id, $element['#auto_select'] ?? TRUE); $form = [ 'source_id' => $source_selector, 'source' => $selected_source ? static::getSourcePluginForm($form_state, $selected_source, $wrapper_id) : [ @@ -291,7 +292,14 @@ class ComponentSlotForm extends ComponentFormBase { ], ], ]; - return empty($slot_id) ? $form : static::addRequired($form, $slot_id); + if (empty($slot_id)) { + return $form; + } + $form = static::addRequired($form, $slot_id); + if (!($element['#wrap'] ?? TRUE)) { + $form = static::addTitleAndDescription($form); + } + return $form; } /** diff --git a/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php b/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php index 1a49db7d..b7bb441f 100644 --- a/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php +++ b/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php @@ -276,6 +276,7 @@ abstract class DerivableContextSourceBase extends SourcePluginBase { '#title' => '', '#source_contexts' => $derived_context, '#cardinality_multiple' => FALSE, + '#auto_select' => FALSE, '#display_remove' => FALSE, "#wrap" => FALSE, '#' . ($is_slot ? 'slot_id' : 'prop_id') => $this->getPropId(), -- GitLab From 3acd9c91644812ad669330990c8d8bcabfc4a1a3 Mon Sep 17 00:00:00 2001 From: just_like_good_vibes <mickael@meulle.com> Date: Fri, 4 Apr 2025 23:20:53 +0200 Subject: [PATCH 2/5] updated --- src/Element/ComponentFormBase.php | 22 ++++++++++++------- src/Element/ComponentPropForm.php | 2 +- src/Element/ComponentSlotForm.php | 2 +- .../Source/DerivableContextSourceBase.php | 7 +++--- 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/Element/ComponentFormBase.php b/src/Element/ComponentFormBase.php index c2fed887..468f9350 100644 --- a/src/Element/ComponentFormBase.php +++ b/src/Element/ComponentFormBase.php @@ -188,11 +188,17 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb * Get source plugin form. */ protected static function getSourcePluginForm(FormStateInterface $form_state, ?SourceInterface $source, string $wrapper_id): array { - $form = $source ? $source->settingsForm([], $form_state) : []; - $form["#type"] = 'container'; - $form['#attributes'] = [ - 'id' => $wrapper_id, - ]; + if (!$source) { + return [ + "#type" => 'container', + "#attributes" => [ + 'id' => $wrapper_id, + ], + ]; + } + $form = $source->settingsForm([], $form_state); + $form['#prefix'] = "<div id='" . $wrapper_id . "'>" . $form['#prefix'] ?? ''; + $form['#suffix'] = ($form['#suffix'] ?? '') . "</div>"; // Weird, but :switchSourceForm() AJAX handler doesn't work without that. foreach (Element::children($form) as $child) { if (isset($form[$child]['#description']) && !isset($form[$child]['#description_display'])) { @@ -221,7 +227,7 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb return $source; } } - if ($auto_select && count($sources) > 0) { + if (($auto_select && count($sources) > 0) || (count($sources) == 1)) { // Default source is in first position. return current($sources); } @@ -325,11 +331,11 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb /** * Build sources selector widget. */ - protected static function buildSourceSelector(array $sources, ?SourceInterface $selected_source, string $wrapper_id, bool $auto_select = TRUE): array { + protected static function buildSourceSelector(array $sources, ?SourceInterface $selected_source, string $wrapper_id): array { if (empty($sources)) { return []; } - if ($auto_select && (count($sources) == 1)) { + if ($selected_source && (count($sources) == 1)) { return [ '#type' => 'hidden', '#value' => array_keys($sources)[0], diff --git a/src/Element/ComponentPropForm.php b/src/Element/ComponentPropForm.php index 5463c524..d8c0bdd0 100644 --- a/src/Element/ComponentPropForm.php +++ b/src/Element/ComponentPropForm.php @@ -88,7 +88,7 @@ class ComponentPropForm extends ComponentFormBase { // ----- $sources = static::getSources($prop_id, $definition, $element); $selected_source = static::getSelectedSource($configuration, $sources, $element['#auto_select'] ?? TRUE); - $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id, $element['#auto_select'] ?? TRUE); + $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id); $source_form = $selected_source ? static::getSourcePluginForm($form_state, $selected_source, $wrapper_id) : [ '#type' => 'container', '#attributes' => [ diff --git a/src/Element/ComponentSlotForm.php b/src/Element/ComponentSlotForm.php index f811653f..8c54bfe6 100644 --- a/src/Element/ComponentSlotForm.php +++ b/src/Element/ComponentSlotForm.php @@ -282,7 +282,7 @@ class ComponentSlotForm extends ComponentFormBase { $wrapper_id = static::getElementId($element, 'ui-patterns-slot-item-' . $slot_id); $sources = static::getSources($slot_id, $definition, $element); $selected_source = static::getSelectedSource($configuration, $sources, $element['#auto_select'] ?? TRUE); - $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id, $element['#auto_select'] ?? TRUE); + $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id); $form = [ 'source_id' => $source_selector, 'source' => $selected_source ? static::getSourcePluginForm($form_state, $selected_source, $wrapper_id) : [ diff --git a/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php b/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php index b7bb441f..36b29e61 100644 --- a/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php +++ b/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php @@ -244,7 +244,7 @@ abstract class DerivableContextSourceBase extends SourcePluginBase { '#tree' => TRUE, ]; if (!$derivable_context || !array_key_exists($derivable_context, $derivableContexts)) { - $form["source"] = $source_container; + $form[$derivable_context ?? ''] = $source_container; return $form; } $source = $this->getSetting($derivable_context) ?? []; @@ -254,7 +254,6 @@ abstract class DerivableContextSourceBase extends SourcePluginBase { $derived_contexts = $derivable_context_plugin->getDerivedContexts(); $form[$derivable_context] = $source_container; if (count($derived_contexts) === 0) { - $form["source"] = $source_container; return $form; } /** @var array<string, mixed> $derivable_context_form */ @@ -271,16 +270,16 @@ abstract class DerivableContextSourceBase extends SourcePluginBase { } $derivable_context_form["value"] = [ '#type' => $is_slot ? 'component_slot_form' : 'component_prop_form', - '#default_value' => $source, '#component_id' => $component_id, '#title' => '', - '#source_contexts' => $derived_context, '#cardinality_multiple' => FALSE, '#auto_select' => FALSE, '#display_remove' => FALSE, "#wrap" => FALSE, '#' . ($is_slot ? 'slot_id' : 'prop_id') => $this->getPropId(), '#tree' => TRUE, + '#default_value' => $source, + '#source_contexts' => $derived_context, '#tag_filter' => $this->getSourcesTagFilter(), ]; return $form; -- GitLab From 12bbf2671f416abf75677fb1e5602a00e2f27af2 Mon Sep 17 00:00:00 2001 From: just_like_good_vibes <mickael@meulle.com> Date: Sat, 5 Apr 2025 00:13:34 +0200 Subject: [PATCH 3/5] updated --- src/Element/ComponentFormBase.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Element/ComponentFormBase.php b/src/Element/ComponentFormBase.php index 468f9350..042e9df3 100644 --- a/src/Element/ComponentFormBase.php +++ b/src/Element/ComponentFormBase.php @@ -197,8 +197,9 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb ]; } $form = $source->settingsForm([], $form_state); - $form['#prefix'] = "<div id='" . $wrapper_id . "'>" . $form['#prefix'] ?? ''; - $form['#suffix'] = ($form['#suffix'] ?? '') . "</div>"; + // @phpstan-ignore-next-line + $form['#prefix'] = "<div id='" . $wrapper_id . "'>" . ($form['#prefix'] ?? ''); + $form['#suffix'] = ($form['#suffix'] ?? '' ) . "</div>"; // Weird, but :switchSourceForm() AJAX handler doesn't work without that. foreach (Element::children($form) as $child) { if (isset($form[$child]['#description']) && !isset($form[$child]['#description_display'])) { -- GitLab From 8915e48aec25c41fcfbb7a3c207d9a74e77031bb Mon Sep 17 00:00:00 2001 From: just_like_good_vibes <mickael@meulle.com> Date: Thu, 10 Apr 2025 13:01:58 +0200 Subject: [PATCH 4/5] phpcs --- src/Element/ComponentFormBase.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Element/ComponentFormBase.php b/src/Element/ComponentFormBase.php index 042e9df3..db9d0c2b 100644 --- a/src/Element/ComponentFormBase.php +++ b/src/Element/ComponentFormBase.php @@ -199,7 +199,7 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb $form = $source->settingsForm([], $form_state); // @phpstan-ignore-next-line $form['#prefix'] = "<div id='" . $wrapper_id . "'>" . ($form['#prefix'] ?? ''); - $form['#suffix'] = ($form['#suffix'] ?? '' ) . "</div>"; + $form['#suffix'] = ($form['#suffix'] ?? '') . "</div>"; // Weird, but :switchSourceForm() AJAX handler doesn't work without that. foreach (Element::children($form) as $child) { if (isset($form[$child]['#description']) && !isset($form[$child]['#description_display'])) { -- GitLab From d09a8c35263a4a74f7da459b71e8f0e9eea58a81 Mon Sep 17 00:00:00 2001 From: just_like_good_vibes <mickael@meulle.com> Date: Fri, 11 Apr 2025 12:31:59 +0200 Subject: [PATCH 5/5] updated --- src/Element/ComponentFormBase.php | 26 ++++++++++++++++--- src/Element/ComponentPropForm.php | 3 +-- src/Element/ComponentSlotForm.php | 3 +-- .../Source/DerivableContextSourceBase.php | 1 - 4 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/Element/ComponentFormBase.php b/src/Element/ComponentFormBase.php index db9d0c2b..08ef1342 100644 --- a/src/Element/ComponentFormBase.php +++ b/src/Element/ComponentFormBase.php @@ -221,16 +221,34 @@ abstract class ComponentFormBase extends FormElementBase implements TrustedCallb /** * Get selected source plugin. */ - protected static function getSelectedSource(array $configuration, array $sources, bool $auto_select = FALSE): ?SourceInterface { + protected static function getSelectedSource(array $configuration, array $sources): ?SourceInterface { $source_id = $configuration['source_id'] ?? NULL; foreach ($sources as $source) { if ($source->getPluginId() === $source_id) { return $source; } } - if (($auto_select && count($sources) > 0) || (count($sources) == 1)) { - // Default source is in first position. - return current($sources); + return static::selectDefaultSource($sources); + } + + /** + * Select default source plugin from a list. + * + * @param array $sources + * The sources. + * + * @return \Drupal\ui_patterns\SourceInterface|null + * The selected source or NULL. + */ + protected static function selectDefaultSource(array $sources): ?SourceInterface { + // Try to return the first widget source. + foreach ($sources as $source) { + /** @var \Drupal\ui_patterns\SourceInterface $source */ + $plugin_definition = $source->getPluginDefinition() ?? []; + $tags = is_array($plugin_definition) ? ($plugin_definition["tags"] ?? []) : []; + if (in_array("widget", $tags)) { + return $source; + } } return NULL; } diff --git a/src/Element/ComponentPropForm.php b/src/Element/ComponentPropForm.php index d8c0bdd0..64f8110f 100644 --- a/src/Element/ComponentPropForm.php +++ b/src/Element/ComponentPropForm.php @@ -54,7 +54,6 @@ class ComponentPropForm extends ComponentFormBase { // Wrapped (into details/summary) or not. '#wrap' => FALSE, '#render_sources' => TRUE, - '#auto_select' => TRUE, '#process' => [ [$class, 'buildForm'], [$class, 'processPropOrSlot'], @@ -87,7 +86,7 @@ class ComponentPropForm extends ComponentFormBase { $wrapper_id = static::getElementId($element, 'ui-patterns-prop-item-' . $prop_id); // ----- $sources = static::getSources($prop_id, $definition, $element); - $selected_source = static::getSelectedSource($configuration, $sources, $element['#auto_select'] ?? TRUE); + $selected_source = static::getSelectedSource($configuration, $sources); $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id); $source_form = $selected_source ? static::getSourcePluginForm($form_state, $selected_source, $wrapper_id) : [ '#type' => 'container', diff --git a/src/Element/ComponentSlotForm.php b/src/Element/ComponentSlotForm.php index 8c54bfe6..d548017b 100644 --- a/src/Element/ComponentSlotForm.php +++ b/src/Element/ComponentSlotForm.php @@ -72,7 +72,6 @@ class ComponentSlotForm extends ComponentFormBase { '#display_weight' => TRUE, '#component_id' => NULL, '#slot_id' => NULL, - '#auto_select' => TRUE, '#cardinality_multiple' => TRUE, '#process' => [ [$class, 'buildForm'], @@ -281,7 +280,7 @@ class ComponentSlotForm extends ComponentFormBase { } $wrapper_id = static::getElementId($element, 'ui-patterns-slot-item-' . $slot_id); $sources = static::getSources($slot_id, $definition, $element); - $selected_source = static::getSelectedSource($configuration, $sources, $element['#auto_select'] ?? TRUE); + $selected_source = static::getSelectedSource($configuration, $sources); $source_selector = static::buildSourceSelector($sources, $selected_source, $wrapper_id); $form = [ 'source_id' => $source_selector, diff --git a/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php b/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php index 36b29e61..f86452e3 100644 --- a/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php +++ b/src/Plugin/UiPatterns/Source/DerivableContextSourceBase.php @@ -273,7 +273,6 @@ abstract class DerivableContextSourceBase extends SourcePluginBase { '#component_id' => $component_id, '#title' => '', '#cardinality_multiple' => FALSE, - '#auto_select' => FALSE, '#display_remove' => FALSE, "#wrap" => FALSE, '#' . ($is_slot ? 'slot_id' : 'prop_id') => $this->getPropId(), -- GitLab