Code Coverage
 
Lines
Branches
Paths
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
HistoryButtons
0.00% covered (danger)
0.00%
0 / 66
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 49
0.00% covered (danger)
0.00%
0 / 5
380
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
 hasButtons
0.00% covered (danger)
0.00%
0 / 17
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
 buildUndoButton
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 8
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 / 8
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 buildClearButton
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 16
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\Island\IslandPluginToolbarButtonConfigurationBase;
11use Drupal\display_builder\Island\IslandReloadEventsTrait;
12use Drupal\display_builder\Island\IslandType;
13
14/**
15 * History buttons island plugin implementation.
16 */
17#[Island(
18  id: 'history',
19  enabled_by_default: TRUE,
20  label: new TranslatableMarkup('History'),
21  description: new TranslatableMarkup('Undo and redo changes.'),
22  type: IslandType::Button,
23  default_region: 'end',
24)]
25class HistoryButtons extends IslandPluginToolbarButtonConfigurationBase {
26
27  use IslandReloadEventsTrait;
28
29  /**
30   * {@inheritdoc}
31   */
32  public function build(InstanceInterface $builder, array $data = [], array $options = []): array {
33    $buttons = [
34      $this->isButtonEnabled('undo') ? $this->buildUndoButton($builder) : [],
35      $this->isButtonEnabled('redo') ? $this->buildRedoButton($builder) : [],
36    ];
37    $clear_button = $this->isButtonEnabled('clear') ? $this->buildClearButton($builder) : [];
38
39    if (empty(\array_filter($buttons))) {
40      return [];
41    }
42
43    $build = [
44      '#type' => 'component',
45      '#component' => 'display_builder:button_group',
46      '#slots' => [
47        'buttons' => $buttons,
48      ],
49    ];
50
51    return [$build, $clear_button];
52  }
53
54  /**
55   * {@inheritdoc}
56   */
57  protected function hasButtons(): array {
58    return [
59      'undo' => [
60        'title' => $this->t('Undo'),
61        'description' => $this->t('Undo action, icon is always visible, label is number of undo.'),
62        'default' => 'icon_label',
63      ],
64      'redo' => [
65        'title' => $this->t('Redo'),
66        'description' => $this->t('Redo action, icon is always visible, label is number of redo.'),
67        'default' => 'icon_label',
68      ],
69      'clear' => [
70        'title' => $this->t('Clear'),
71        'description' => $this->t('A button to clear the logs history (past and future).'),
72        'default' => 'hidden',
73      ],
74    ];
75  }
76
77  /**
78   * Builds the undo button.
79   *
80   * @param \Drupal\display_builder\InstanceInterface $builder
81   *   The builder instance.
82   *
83   * @return array
84   *   The undo button render array.
85   */
86  private function buildUndoButton(InstanceInterface $builder): array {
87    $past = $builder->getPast();
88    $undo = $this->buildButton(
89      ($this->showLabel('undo') && $past) ? (string) \count($past) : '',
90      'undo',
91      'arrow-counterclockwise',
92      $this->t('Undo (shortcut: Ctrl/Cmd+Z)'),
93      ['mod+z u' => $this->t('Undo last change')]
94    );
95
96    if (empty($past)) {
97      $undo['#attributes']['disabled'] = 'disabled';
98    }
99
100    return $this->htmxEvents->onUndo($undo, (string) $builder->id());
101  }
102
103  /**
104   * Builds the redo button.
105   *
106   * @param \Drupal\display_builder\InstanceInterface $builder
107   *   The builder instance.
108   *
109   * @return array
110   *   The redo button render array.
111   */
112  private function buildRedoButton(InstanceInterface $builder): array {
113    $future = $builder->getFuture();
114    $redo = $this->buildButton(
115      ($this->showLabel('redo') && $future) ? (string) \count($future) : '',
116      'redo',
117      'arrow-clockwise',
118      $this->t('Redo (shortcut: Ctrl/Cmd+Shift+Z)'),
119      ['mod+shift+z r' => $this->t('Redo last undone change')]
120    );
121
122    if (empty($future)) {
123      $redo['#attributes']['disabled'] = 'disabled';
124    }
125
126    return $this->htmxEvents->onRedo($redo, (string) $builder->id());
127  }
128
129  /**
130   * Builds the clear button.
131   *
132   * @param \Drupal\display_builder\InstanceInterface $builder
133   *   The builder instance.
134   *
135   * @return array
136   *   The clear button render array.
137   */
138  private function buildClearButton(InstanceInterface $builder): array {
139    $clear = $this->buildButton(
140      $this->showLabel('clear') ? $this->t('Clear') : '',
141      'clear',
142      $this->showIcon('clear') ? 'clock-history' : '',
143      $this->t('Clear history (shortcut: Shift+C)'),
144      ['shift+c' => $this->t('Clear all changes history')]
145    );
146    $clear['#props']['variant'] = 'warning';
147    $clear['#attributes']['outline'] = TRUE;
148
149    if (empty($builder->getPast()) && empty($builder->getFuture())) {
150      $clear['#attributes']['class'] = ['hidden'];
151    }
152
153    return $this->htmxEvents->onClear($clear, (string) $builder->id());
154  }
155
156}