Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 64
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
StylesPanel
0.00% covered (danger)
0.00%
0 / 58
0.00% covered (danger)
0.00%
0 / 21
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 10
240
0.00% covered (danger)
0.00%
0 / 1
 create
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 buildForm
0.00% covered (danger)
0.00%
0 / 9
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 validateForm
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 alterElement
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getSummary
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
 onAttachToRoot
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onAttachToSlot
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onActive
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 onDelete
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 isApplicable
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
12
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder\Plugin\display_builder\Island;
6
7use Drupal\Core\Extension\ModuleHandlerInterface;
8use Drupal\Core\Form\FormStateInterface;
9use Drupal\Core\StringTranslation\TranslatableMarkup;
10use Drupal\display_builder\Attribute\Island;
11use Drupal\display_builder\InstanceInterface;
12use Drupal\display_builder\Island\IslandPluginBase;
13use Drupal\display_builder\Island\IslandType;
14use Drupal\display_builder\Island\IslandWithFormInterface;
15use Drupal\display_builder\Island\IslandWithFormTrait;
16use Drupal\display_builder\Island\RenderableAltererInterface;
17use Drupal\display_builder\ThirdPartySettingsInterface;
18use Drupal\ui_styles\StylePluginManagerInterface;
19use Symfony\Component\DependencyInjection\ContainerInterface;
20
21/**
22 * Styles island plugin implementation.
23 *
24 * @todo must move to UI Styles module.
25 */
26#[Island(
27  id: 'styles',
28  label: new TranslatableMarkup('Styles'),
29  description: new TranslatableMarkup('Apply style utilities to the active component or block'),
30  type: IslandType::Contextual,
31  modules: ['ui_styles'],
32)]
33class StylesPanel extends IslandPluginBase implements IslandWithFormInterface, RenderableAltererInterface, ThirdPartySettingsInterface {
34
35  use IslandWithFormTrait;
36
37  /**
38   * The UI Styles styles manager.
39   */
40  protected StylePluginManagerInterface $stylesManager;
41
42  /**
43   * The module handler.
44   */
45  protected ModuleHandlerInterface $moduleHandler;
46
47  /**
48   * {@inheritdoc}
49   */
50  public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static {
51    $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition);
52    $instance->stylesManager = $container->get('plugin.manager.ui_styles');
53    $instance->moduleHandler = $container->get('module_handler');
54
55    return $instance;
56  }
57
58  /**
59   * {@inheritdoc}
60   */
61  public function buildForm(array &$form, FormStateInterface $form_state): void {
62    // The data to be received here is in the form of:
63    // ['styles' => ['selected' => [], 'extra' => '']].
64    $form += [
65      'styles' => [
66        '#type' => 'ui_styles_styles',
67        '#title' => $this->t('Styles'),
68        '#wrapper_type' => 'div',
69        '#default_value' => \array_merge(['selected' => [], 'extra' => ''], $this->data ?? []),
70      ],
71      '#tree' => TRUE,
72    ];
73  }
74
75  /**
76   * {@inheritdoc}
77   */
78  public function validateForm(array &$form, FormStateInterface $form_state): void {
79    // The styles key in the values is added by BlockStylesForm.
80    // Inside the styles key, there are two keys: selected and extra.
81    // The structure here is the one produced by UI styles Form API element.
82    $values = $form_state->getValue('styles');
83    $form_state->setValue('selected', $values['selected'] ?? []);
84    $form_state->setValue('extra', $values['extra'] ?? '');
85    $form_state->unsetValue('styles');
86    // Those two lines are necessary to prevent the form from being rebuilt.
87    // if rebuilt, the form state values will have both the computed ones
88    // and the raw ones (wrapper key and values).
89    $form_state->setRebuild(FALSE);
90    $form_state->setExecuted();
91  }
92
93  /**
94   * {@inheritdoc}
95   */
96  public function alterElement(array $element, array $data = []): array {
97    $selected = $data['selected'] ?? [];
98    $extra = $data['extra'] ?? '';
99
100    return $this->stylesManager->addClasses($element, $selected, $extra);
101  }
102
103  /**
104   * {@inheritdoc}
105   */
106  public function getSummary(): ?array {
107    if (empty($this->data['selected'])) {
108      // We do not cover 'extra'.
109      return NULL;
110    }
111
112    $items = [];
113
114    foreach ($this->data['selected'] ?? [] as $style_id => $option_key) {
115      $style = $this->stylesManager->getDefinition($style_id);
116      $options = $style->getOptionsAsOptions();
117      $option = $options[$option_key] ?? $option_key;
118      $item = \sprintf('%s %s', $option, \strtolower((string) $style->getLabel()));
119      $items[] = [
120        '#type' => 'html_tag',
121        '#tag' => 'li',
122        '#value' => $item,
123      ];
124    }
125
126    if (empty($items)) {
127      return NULL;
128    }
129
130    $summary = [
131      [
132        '#type' => 'html_tag',
133        '#tag' => 'em',
134        '#value' => new TranslatableMarkup('Styles'),
135      ],
136      [
137        '#type' => 'html_tag',
138        '#tag' => 'ul',
139        '#attributes' => [
140          'class' => ['summary'],
141        ],
142        0 => $items,
143      ],
144    ];
145
146    return $summary;
147  }
148
149  /**
150   * {@inheritdoc}
151   */
152  public function onAttachToRoot(InstanceInterface $instance, string $node_id): array {
153    return $this->reloadWithNodeData($instance, $node_id);
154  }
155
156  /**
157   * {@inheritdoc}
158   */
159  public function onAttachToSlot(InstanceInterface $instance, string $node_id, string $parent_id): array {
160    return $this->reloadWithNodeData($instance, $node_id);
161  }
162
163  /**
164   * {@inheritdoc}
165   */
166  public function onActive(InstanceInterface $instance, array $data): array {
167    return $this->reloadWithLocalData($instance, $data);
168  }
169
170  /**
171   * {@inheritdoc}
172   */
173  public function onDelete(InstanceInterface $instance, ?string $parent_id): array {
174    return $this->reloadWithLocalData($instance, []);
175  }
176
177  /**
178   * {@inheritdoc}
179   */
180  public function isApplicable(): bool {
181    return parent::isApplicable() && !empty($this->data) && $this->moduleHandler->moduleExists('ui_styles');
182  }
183
184}