Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 91
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 12
CRAP
0.00% covered (danger)
0.00%
0 / 1
HistoryButtons
0.00% covered (danger)
0.00%
0 / 85
0.00% covered (danger)
0.00%
0 / 46
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 12
756
0.00% covered (danger)
0.00%
0 / 1
 build
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
30
 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
 onMove
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
 onHistoryChange
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
 onUpdate
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
 hasButtons
0.00% covered (danger)
0.00%
0 / 20
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
 rebuild
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
6
 buildUndoButton
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 buildRedoButton
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
20
 buildClearButton
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
30
1<?php
2
3declare(strict_types=1);
4
5namespace Drupal\display_builder\Plugin\display_builder\Island;
6
7use Drupal\Core\StringTranslation\TranslatableMarkup;
8use Drupal\display_builder\Attribute\Island;
9use Drupal\display_builder\InstanceInterface;
10use Drupal\display_builder\IslandPluginToolbarButtonConfigurationBase;
11use Drupal\display_builder\IslandType;
12
13/**
14 * History buttons island plugin implementation.
15 */
16#[Island(
17  id: 'history',
18  enabled_by_default: TRUE,
19  label: new TranslatableMarkup('History'),
20  description: new TranslatableMarkup('Undo and redo changes.'),
21  type: IslandType::Button,
22)]
23class HistoryButtons extends IslandPluginToolbarButtonConfigurationBase {
24
25  /**
26   * {@inheritdoc}
27   */
28  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
29    $builder_id = (string) $builder->id();
30    $buttons = [
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
32      $this->isButtonEnabled('redo') ? $this->buildRedoButton($builder, $builder_id) : [],
33      $this->isButtonEnabled('clear') ? $this->buildClearButton($builder, $builder_id) : [],
34    ];
35
36    if (empty(\array_filter($buttons))) {
37      return [];
38    }
39
40    return [
41      '#type' => 'component',
42      '#component' => 'display_builder:button_group',
43      '#slots' => [
44        'buttons' => $buttons,
45      ],
46    ];
47  }
48
49  /**
50   * {@inheritdoc}
51   */
52  public function onAttachToRoot(string $builder_id, string $instance_id): array {
53    return $this->rebuild($builder_id);
54  }
55
56  /**
57   * {@inheritdoc}
58   */
59  public function onAttachToSlot(string $builder_id, string $instance_id, string $parent_id): array {
60    return $this->rebuild($builder_id);
61  }
62
63  /**
64   * {@inheritdoc}
65   */
66  public function onMove(string $builder_id, string $instance_id): array {
67    return $this->rebuild($builder_id);
68  }
69
70  /**
71   * {@inheritdoc}
72   */
73  public function onHistoryChange(string $builder_id): array {
74    return $this->rebuild($builder_id);
75  }
76
77  /**
78   * {@inheritdoc}
79   */
80  public function onUpdate(string $builder_id, string $instance_id): array {
81    return $this->rebuild($builder_id);
82  }
83
84  /**
85   * {@inheritdoc}
86   */
87  public function onDelete(string $builder_id, string $parent_id): array {
88    return $this->rebuild($builder_id);
89  }
90
91  /**
92   * {@inheritdoc}
93   */
94  protected function hasButtons(): array {
95    return [
96      'undo' => [
97        'title' => $this->t('Undo'),
98        'description' => $this->t('Undo action, icon is always visible, label is number of undo.'),
99        'default' => 'icon_label',
100        'remove' => 'icon',
101      ],
102      'redo' => [
103        'title' => $this->t('Redo'),
104        'description' => $this->t('Redo action, icon is always visible, label is number of redo.'),
105        'default' => 'icon_label',
106        'remove' => 'icon',
107      ],
108      'clear' => [
109        'title' => $this->t('Clear'),
110        'description' => $this->t('A button to clear the logs history (past and future).'),
111        'default' => 'hidden',
112        'remove' => 'icon',
113      ],
114    ];
115  }
116
117  /**
118   * Rebuilds the island with the given builder ID.
119   *
120   * @param string $builder_id
121   *   The ID of the builder.
122   *
123   * @return array
124   *   The rebuilt island.
125   */
126  private function rebuild(string $builder_id): array {
127    if (!$this->builder) {
128      // @todo pass \Drupal\display_builder\InstanceInterface object in
129      // parameters instead of loading again.
130      /** @var \Drupal\display_builder\InstanceInterface $builder */
131      $builder = $this->entityTypeManager->getStorage('display_builder_instance')->load($builder_id);
132      $this->builder = $builder;
133    }
134
135    return $this->addOutOfBand(
136      $this->build($this->builder),
137      '#' . $this->getHtmlId($builder_id),
138      'innerHTML'
139    );
140  }
141
142  /**
143   * Builds the undo button.
144   *
145   * @param \Drupal\display_builder\InstanceInterface $builder
146   *   The builder instance.
147   * @param string $builder_id
148   *   The builder ID.
149   *
150   * @return array
151   *   The undo button render array.
152   */
153  private function buildUndoButton(InstanceInterface $builder, string $builder_id): array {
154    $past = $builder->getCountPast();
155    $undo = $this->buildButton(
156      ($this->showLabel('undo') && $past) ? (string) $past : '',
157      'undo',
158      'arrow-counterclockwise',
159      $this->t('Undo (shortcut: u)'),
160      ['u' => $this->t('Undo last change')]
161    );
162
163    if (empty($past)) {
164      $undo['#attributes']['disabled'] = 'disabled';
165    }
166
167    return $this->htmxEvents->onUndo($undo, $builder_id);
168  }
169
170  /**
171   * Builds the redo button.
172   *
173   * @param \Drupal\display_builder\InstanceInterface $builder
174   *   The builder instance.
175   * @param string $builder_id
176   *   The builder ID.
177   *
178   * @return array
179   *   The redo button render array.
180   */
181  private function buildRedoButton(InstanceInterface $builder, string $builder_id): array {
182    $future = $builder->getCountFuture();
183    $redo = $this->buildButton(
184      ($this->showLabel('redo') && $future) ? (string) $future : '',
185      'redo',
186      'arrow-clockwise',
187      $this->t('Redo (shortcut: r)'),
188      ['r' => $this->t('Redo last undone change')]
189    );
190
191    if (empty($future)) {
192      $redo['#attributes']['disabled'] = 'disabled';
193    }
194
195    return $this->htmxEvents->onRedo($redo, $builder_id);
196  }
197
198  /**
199   * Builds the clear button.
200   *
201   * @param \Drupal\display_builder\InstanceInterface $builder
202   *   The builder instance.
203   * @param string $builder_id
204   *   The builder ID.
205   *
206   * @return array
207   *   The clear button render array.
208   */
209  private function buildClearButton(InstanceInterface $builder, string $builder_id): array {
210    $past = $builder->getCountPast();
211    $future = $builder->getCountFuture();
212    $clear = $this->buildButton(
213      $this->showLabel('clear') ? $this->t('Clear') : '',
214      'clear',
215      $this->showIcon('clear') ? 'clock-history' : '',
216      $this->t('Clear history (shortcut: C)'),
217      ['C' => $this->t('Clear all changes history')]
218    );
219    $clear['#props']['variant'] = 'warning';
220    $clear['#attributes']['outline'] = TRUE;
221
222    if (empty($past) && empty($future)) {
223      $clear['#attributes']['class'] = ['hidden'];
224    }
225
226    return $this->htmxEvents->onClear($clear, $builder_id);
227  }
228
229}

Branches

Below are the source code lines that represent each code branch as identified by Xdebug. Please note a branch is not necessarily coterminous with a line, a line may contain multiple branches and therefore show up more than once. Please also be aware that some branches may be implicit rather than explicit, e.g. an if statement always has an else as part of its logical flow even if you didn't write one.

HistoryButtons->build
28  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
29    $builder_id = (string) $builder->id();
30    $buttons = [
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
32      $this->isButtonEnabled('redo') ? $this->buildRedoButton($builder, $builder_id) : [],
32      $this->isButtonEnabled('redo') ? $this->buildRedoButton($builder, $builder_id) : [],
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
32      $this->isButtonEnabled('redo') ? $this->buildRedoButton($builder, $builder_id) : [],
33      $this->isButtonEnabled('clear') ? $this->buildClearButton($builder, $builder_id) : [],
33      $this->isButtonEnabled('clear') ? $this->buildClearButton($builder, $builder_id) : [],
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
31      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder, $builder_id) : [],
32      $this->isButtonEnabled('redo') ? $this->buildRedoButton($builder, $builder_id) : [],
33      $this->isButtonEnabled('clear') ? $this->buildClearButton($builder, $builder_id) : [],
34    ];
35
36    if (empty(\array_filter($buttons))) {
37      return [];
41      '#type' => 'component',
42      '#component' => 'display_builder:button_group',
43      '#slots' => [
44        'buttons' => $buttons,
HistoryButtons->buildClearButton
209  private function buildClearButton(InstanceInterface $builder, string $builder_id): array {
210    $past = $builder->getCountPast();
211    $future = $builder->getCountFuture();
212    $clear = $this->buildButton(
213      $this->showLabel('clear') ? $this->t('Clear') : '',
213      $this->showLabel('clear') ? $this->t('Clear') : '',
213      $this->showLabel('clear') ? $this->t('Clear') : '',
213      $this->showLabel('clear') ? $this->t('Clear') : '',
214      'clear',
215      $this->showIcon('clear') ? 'clock-history' : '',
215      $this->showIcon('clear') ? 'clock-history' : '',
215      $this->showIcon('clear') ? 'clock-history' : '',
215      $this->showIcon('clear') ? 'clock-history' : '',
216      $this->t('Clear history (shortcut: C)'),
217      ['C' => $this->t('Clear all changes history')]
218    );
219    $clear['#props']['variant'] = 'warning';
220    $clear['#attributes']['outline'] = TRUE;
221
222    if (empty($past) && empty($future)) {
222    if (empty($past) && empty($future)) {
223      $clear['#attributes']['class'] = ['hidden'];
224    }
225
226    return $this->htmxEvents->onClear($clear, $builder_id);
226    return $this->htmxEvents->onClear($clear, $builder_id);
HistoryButtons->buildRedoButton
181  private function buildRedoButton(InstanceInterface $builder, string $builder_id): array {
182    $future = $builder->getCountFuture();
183    $redo = $this->buildButton(
184      ($this->showLabel('redo') && $future) ? (string) $future : '',
184      ($this->showLabel('redo') && $future) ? (string) $future : '',
184      ($this->showLabel('redo') && $future) ? (string) $future : '',
184      ($this->showLabel('redo') && $future) ? (string) $future : '',
184      ($this->showLabel('redo') && $future) ? (string) $future : '',
185      'redo',
186      'arrow-clockwise',
187      $this->t('Redo (shortcut: r)'),
188      ['r' => $this->t('Redo last undone change')]
189    );
190
191    if (empty($future)) {
192      $redo['#attributes']['disabled'] = 'disabled';
193    }
194
195    return $this->htmxEvents->onRedo($redo, $builder_id);
195    return $this->htmxEvents->onRedo($redo, $builder_id);
HistoryButtons->buildUndoButton
153  private function buildUndoButton(InstanceInterface $builder, string $builder_id): array {
154    $past = $builder->getCountPast();
155    $undo = $this->buildButton(
156      ($this->showLabel('undo') && $past) ? (string) $past : '',
156      ($this->showLabel('undo') && $past) ? (string) $past : '',
156      ($this->showLabel('undo') && $past) ? (string) $past : '',
156      ($this->showLabel('undo') && $past) ? (string) $past : '',
156      ($this->showLabel('undo') && $past) ? (string) $past : '',
157      'undo',
158      'arrow-counterclockwise',
159      $this->t('Undo (shortcut: u)'),
160      ['u' => $this->t('Undo last change')]
161    );
162
163    if (empty($past)) {
164      $undo['#attributes']['disabled'] = 'disabled';
165    }
166
167    return $this->htmxEvents->onUndo($undo, $builder_id);
167    return $this->htmxEvents->onUndo($undo, $builder_id);
HistoryButtons->hasButtons
97        'title' => $this->t('Undo'),
98        'description' => $this->t('Undo action, icon is always visible, label is number of undo.'),
99        'default' => 'icon_label',
100        'remove' => 'icon',
101      ],
102      'redo' => [
103        'title' => $this->t('Redo'),
104        'description' => $this->t('Redo action, icon is always visible, label is number of redo.'),
105        'default' => 'icon_label',
106        'remove' => 'icon',
107      ],
108      'clear' => [
109        'title' => $this->t('Clear'),
110        'description' => $this->t('A button to clear the logs history (past and future).'),
111        'default' => 'hidden',
112        'remove' => 'icon',
HistoryButtons->onAttachToRoot
52  public function onAttachToRoot(string $builder_id, string $instance_id): array {
53    return $this->rebuild($builder_id);
HistoryButtons->onAttachToSlot
59  public function onAttachToSlot(string $builder_id, string $instance_id, string $parent_id): array {
60    return $this->rebuild($builder_id);
HistoryButtons->onDelete
87  public function onDelete(string $builder_id, string $parent_id): array {
88    return $this->rebuild($builder_id);
HistoryButtons->onHistoryChange
73  public function onHistoryChange(string $builder_id): array {
74    return $this->rebuild($builder_id);
HistoryButtons->onMove
66  public function onMove(string $builder_id, string $instance_id): array {
67    return $this->rebuild($builder_id);
HistoryButtons->onUpdate
80  public function onUpdate(string $builder_id, string $instance_id): array {
81    return $this->rebuild($builder_id);
HistoryButtons->rebuild
126  private function rebuild(string $builder_id): array {
127    if (!$this->builder) {
131      $builder = $this->entityTypeManager->getStorage('display_builder_instance')->load($builder_id);
132      $this->builder = $builder;
133    }
134
135    return $this->addOutOfBand(
135    return $this->addOutOfBand(
136      $this->build($this->builder),
137      '#' . $this->getHtmlId($builder_id),
138      'innerHTML'