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