Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 100 |
|
0.00% |
0 / 6 |
CRAP | |
0.00% |
0 / 1 |
TreePanel | |
0.00% |
0 / 94 |
|
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 / 8 |
|
0.00% |
0 / 1 |
2 | |||
buildSingleComponent | |
0.00% |
0 / 54 |
|
0.00% |
0 / 1 |
90 | |||
buildSingleBlock | |
0.00% |
0 / 18 |
|
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: 'tree', |
19 | label: new TranslatableMarkup('Tree'), |
20 | description: new TranslatableMarkup('Manageable hierarchical tree view of elements.'), |
21 | type: IslandType::View, |
22 | icon: 'bar-chart-steps', |
23 | )] |
24 | class TreePanel 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 | 't' => t('Show the tree'), |
47 | ]; |
48 | } |
49 | |
50 | /** |
51 | * {@inheritdoc} |
52 | */ |
53 | public function build(InstanceInterface $builder, array $data = [], array $options = []): array { |
54 | $builder_id = (string) $builder->id(); |
55 | |
56 | return [ |
57 | '#type' => 'component', |
58 | '#component' => 'display_builder:panel_tree', |
59 | '#slots' => [ |
60 | 'items' => $this->digFromSlot($builder_id, $data), |
61 | ], |
62 | ]; |
63 | } |
64 | |
65 | /** |
66 | * {@inheritdoc} |
67 | */ |
68 | public function buildSingleComponent(string $builder_id, string $instance_id, array $data, int $index = 0): array { |
69 | $component_id = $data['source']['component']['component_id'] ?? NULL; |
70 | $instance_id = $instance_id ?: $data['_node_id']; |
71 | |
72 | if (!$instance_id && !$component_id) { |
73 | return []; |
74 | } |
75 | |
76 | $component = $this->sdcManager->getDefinition($component_id); |
77 | |
78 | if (!$component) { |
79 | return []; |
80 | } |
81 | |
82 | $slots = []; |
83 | |
84 | foreach ($component['slots'] ?? [] as $slot_id => $definition) { |
85 | $items = [ |
86 | '#type' => 'component', |
87 | '#component' => 'display_builder:tree_item', |
88 | '#props' => [ |
89 | 'icon' => 'box-arrow-in-right', |
90 | ], |
91 | '#slots' => [ |
92 | 'title' => $definition['title'], |
93 | ], |
94 | // Slot is needed for contextual menu paste. |
95 | // @see assets/js/contextual_menu.js |
96 | '#attributes' => [ |
97 | 'data-slot-id' => $slot_id, |
98 | 'data-slot-title' => $definition['title'], |
99 | 'data-node-id' => $instance_id, |
100 | 'data-node-title' => $component['label'], |
101 | 'data-menu-type' => 'slot', |
102 | ], |
103 | ]; |
104 | |
105 | if (isset($data['source']['component']['slots'][$slot_id]['sources'])) { |
106 | $sources = $data['source']['component']['slots'][$slot_id]['sources']; |
107 | $items['#slots']['children'] = $this->digFromSlot($builder_id, $sources); |
108 | } |
109 | |
110 | $slots[] = $items; |
111 | } |
112 | |
113 | // I f a single item, expand by default. |
114 | if (\count($slots) === 1) { |
115 | $slots[0]['#props']['expanded'] = TRUE; |
116 | } |
117 | |
118 | $name = $component['name']; |
119 | $variant = $this->getComponentVariantLabel($data, $component); |
120 | |
121 | if ($variant) { |
122 | $name .= ' - ' . $variant; |
123 | } |
124 | |
125 | return [ |
126 | '#type' => 'component', |
127 | '#component' => 'display_builder:tree_item', |
128 | '#props' => [ |
129 | 'expanded' => TRUE, |
130 | 'icon' => 'box', |
131 | ], |
132 | '#slots' => [ |
133 | 'title' => $name, |
134 | 'children' => $slots, |
135 | ], |
136 | // Required for the context menu label. |
137 | // @see assets/js/contextual_menu.js |
138 | '#attributes' => [ |
139 | 'data-node-id' => $instance_id, |
140 | 'data-node-title' => $name, |
141 | 'data-slot-position' => $index, |
142 | 'data-menu-type' => 'component', |
143 | ], |
144 | ]; |
145 | } |
146 | |
147 | /** |
148 | * {@inheritdoc} |
149 | */ |
150 | public function buildSingleBlock(string $builder_id, string $instance_id, array $data, int $index = 0): array { |
151 | $instance_id = $instance_id ?: $data['_node_id']; |
152 | $label = $this->slotSourceProxy->getLabelWithSummary($data, $this->configuration['contexts'] ?? []); |
153 | |
154 | return [ |
155 | '#type' => 'component', |
156 | '#component' => 'display_builder:tree_item', |
157 | '#props' => [ |
158 | 'icon' => 'view-list', |
159 | ], |
160 | '#slots' => [ |
161 | 'title' => $label['summary'], |
162 | ], |
163 | '#attributes' => [ |
164 | 'data-node-id' => $instance_id, |
165 | // This label is used for contextual menu. |
166 | // @see assets/js/contextual_menu.js |
167 | 'data-node-title' => $label['label'], |
168 | 'data-slot-position' => $index, |
169 | 'data-menu-type' => 'block', |
170 | ], |
171 | ]; |
172 | } |
173 | |
174 | /** |
175 | * Get the label for a component variant. |
176 | * |
177 | * @param array $data |
178 | * The component data array. |
179 | * @param array $definition |
180 | * The component definition array. |
181 | * |
182 | * @return string |
183 | * The variant label or empty string if no variant is set. |
184 | */ |
185 | private function getComponentVariantLabel(array $data, array $definition): string { |
186 | if (!isset($data['source']['component']['variant_id'])) { |
187 | return ''; |
188 | } |
189 | |
190 | if ($data['source']['component']['variant_id']['source_id'] !== 'select') { |
191 | return ''; |
192 | } |
193 | $variant_id = $data['source']['component']['variant_id']['source']['value'] ?? ''; |
194 | |
195 | if (empty($variant_id)) { |
196 | return ''; |
197 | } |
198 | |
199 | return $definition['variants'][$variant_id]['title'] ?? ''; |
200 | } |
201 | |
202 | } |