Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 88 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
LayersPanel | |
0.00% |
0 / 82 |
|
0.00% |
0 / 6 |
342 | |
0.00% |
0 / 1 |
create | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
keyboardShortcuts | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
2 | |||
build | |
0.00% |
0 / 7 |
|
0.00% |
0 / 1 |
6 | |||
buildSingleComponent | |
0.00% |
0 / 49 |
|
0.00% |
0 / 1 |
72 | |||
buildSingleBlock | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
6 | |||
getComponentVariantLabel | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
20 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace Drupal\display_builder\Plugin\display_builder\Island; |
6 | |
7 | use Drupal\Core\StringTranslation\TranslatableMarkup; |
8 | use Drupal\display_builder\Attribute\Island; |
9 | use Drupal\display_builder\InstanceInterface; |
10 | use Drupal\display_builder\IslandType; |
11 | use Drupal\display_builder\SlotSourceProxy; |
12 | use Symfony\Component\DependencyInjection\ContainerInterface; |
13 | |
14 | /** |
15 | * Layers island plugin implementation. |
16 | */ |
17 | #[Island( |
18 | id: 'layers', |
19 | label: new TranslatableMarkup('Layers'), |
20 | description: new TranslatableMarkup('Manageable hierarchical layer view of elements.'), |
21 | type: IslandType::View, |
22 | icon: 'layers', |
23 | )] |
24 | class LayersPanel extends BuilderPanel { |
25 | |
26 | /** |
27 | * Proxy for slot source operations. |
28 | */ |
29 | protected SlotSourceProxy $slotSourceProxy; |
30 | |
31 | /** |
32 | * {@inheritdoc} |
33 | */ |
34 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static { |
35 | $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); |
36 | $instance->slotSourceProxy = $container->get('display_builder.slot_sources_proxy'); |
37 | |
38 | return $instance; |
39 | } |
40 | |
41 | /** |
42 | * {@inheritdoc} |
43 | */ |
44 | public static function keyboardShortcuts(): array { |
45 | return [ |
46 | 'y' => t('Show the layer'), |
47 | ]; |
48 | } |
49 | |
50 | /** |
51 | * {@inheritdoc} |
52 | */ |
53 | public function build(InstanceInterface $builder, array $data = [], array $options = []): array { |
54 | $build = parent::build($builder, $data, $options); |
55 | |
56 | if (empty($build['#slots']['content'] ?? [])) { |
57 | // Load en empty component to have any assets with it. |
58 | $build['#slots']['content'] = [ |
59 | '#type' => 'component', |
60 | '#component' => 'display_builder:layer', |
61 | ]; |
62 | } |
63 | |
64 | return $build; |
65 | } |
66 | |
67 | /** |
68 | * {@inheritdoc} |
69 | */ |
70 | public function buildSingleComponent(string $builder_id, string $instance_id, array $data, int $index = 0): array { |
71 | $component_id = $data['source']['component']['component_id'] ?? NULL; |
72 | $instance_id = $instance_id ?: $data['_node_id']; |
73 | |
74 | if (!$instance_id && !$component_id) { |
75 | return []; |
76 | } |
77 | |
78 | $component = $this->sdcManager->getDefinition($component_id); |
79 | |
80 | if (!$component) { |
81 | return []; |
82 | } |
83 | |
84 | $slots = []; |
85 | |
86 | foreach ($component['slots'] ?? [] as $slot_id => $definition) { |
87 | $dropzone = [ |
88 | '#type' => 'component', |
89 | '#component' => 'display_builder:dropzone', |
90 | '#props' => [ |
91 | 'title' => $definition['title'], |
92 | 'variant' => 'highlighted', |
93 | ], |
94 | '#attributes' => [ |
95 | // Required for JavaScript @see components/dropzone/dropzone.js. |
96 | 'data-db-id' => $builder_id, |
97 | // Slot is needed for contextual menu paste. |
98 | // @see assets/js/contextual_menu.js |
99 | 'data-slot-id' => $slot_id, |
100 | 'data-slot-title' => $definition['title'], |
101 | 'data-node-title' => $component['label'], |
102 | ], |
103 | ]; |
104 | |
105 | if (isset($data['source']['component']['slots'][$slot_id]['sources'])) { |
106 | $sources = $data['source']['component']['slots'][$slot_id]['sources']; |
107 | $dropzone['#slots']['content'] = $this->digFromSlot($builder_id, $sources); |
108 | } |
109 | $dropzone = $this->htmxEvents->onSlotDrop($dropzone, $builder_id, $this->getPluginID(), $instance_id, $slot_id); |
110 | $slots[] = [ |
111 | [ |
112 | '#plain_text' => $definition['title'], |
113 | ], |
114 | $dropzone, |
115 | ]; |
116 | } |
117 | $name = $component['name']; |
118 | $variant = $this->getComponentVariantLabel($data, $component); |
119 | |
120 | if ($variant) { |
121 | $name .= ' - ' . $variant; |
122 | } |
123 | |
124 | $build = [ |
125 | '#type' => 'component', |
126 | '#component' => 'display_builder:layer', |
127 | '#slots' => [ |
128 | 'title' => $name, |
129 | 'children' => $slots, |
130 | ], |
131 | // Required for the context menu label. |
132 | // @see assets/js/contextual_menu.js |
133 | '#attributes' => [ |
134 | 'data-node-title' => $name, |
135 | ], |
136 | ]; |
137 | |
138 | return $this->htmxEvents->onInstanceClick($build, $builder_id, $instance_id, (string) $component['label'], $index); |
139 | } |
140 | |
141 | /** |
142 | * {@inheritdoc} |
143 | */ |
144 | public function buildSingleBlock(string $builder_id, string $instance_id, array $data, int $index = 0): array { |
145 | $label = $this->slotSourceProxy->getLabelWithSummary($data, $this->configuration['contexts'] ?? []); |
146 | $build = [ |
147 | '#type' => 'component', |
148 | '#component' => 'display_builder:layer', |
149 | '#slots' => [ |
150 | 'title' => $label['summary'], |
151 | ], |
152 | ]; |
153 | $instance_id = $instance_id ?: $data['_node_id']; |
154 | |
155 | // This label is used for contextual menu. |
156 | // @see assets/js/contextual_menu.js |
157 | $build['#attributes']['data-node-title'] = $label['summary']; |
158 | $build['#attributes']['data-slot-position'] = $index; |
159 | |
160 | return $this->htmxEvents->onInstanceClick($build, $builder_id, $instance_id, $label['label'], $index); |
161 | } |
162 | |
163 | /** |
164 | * Get the label for a component variant. |
165 | * |
166 | * @param array $data |
167 | * The component data array. |
168 | * @param array $definition |
169 | * The component definition array. |
170 | * |
171 | * @return string |
172 | * The variant label or empty string if no variant is set. |
173 | */ |
174 | private function getComponentVariantLabel(array $data, array $definition): string { |
175 | if (!isset($data['source']['component']['variant_id'])) { |
176 | return ''; |
177 | } |
178 | |
179 | if ($data['source']['component']['variant_id']['source_id'] !== 'select') { |
180 | return ''; |
181 | } |
182 | $variant_id = $data['source']['component']['variant_id']['source']['value'] ?? ''; |
183 | |
184 | if (empty($variant_id)) { |
185 | return ''; |
186 | } |
187 | |
188 | return $definition['variants'][$variant_id]['title'] ?? ''; |
189 | } |
190 | |
191 | } |