Code Coverage |
||||||||||||||||
Lines |
Branches |
Paths |
Functions and Methods |
Classes and Traits |
||||||||||||
| Total | |
0.00% |
0 / 133 |
|
0.00% |
0 / 46 |
|
0.00% |
0 / 52 |
|
0.00% |
0 / 7 |
CRAP | |
0.00% |
0 / 1 |
| LayersPanel | |
0.00% |
0 / 126 |
|
0.00% |
0 / 46 |
|
0.00% |
0 / 52 |
|
0.00% |
0 / 7 |
756 | |
0.00% |
0 / 1 |
| create | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| keyboardShortcuts | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
| build | |
0.00% |
0 / 7 |
|
0.00% |
0 / 3 |
|
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
6 | |||
| buildSingleComponent | |
0.00% |
0 / 54 |
|
0.00% |
0 / 12 |
|
0.00% |
0 / 20 |
|
0.00% |
0 / 1 |
56 | |||
| buildSingleBlock | |
0.00% |
0 / 21 |
|
0.00% |
0 / 9 |
|
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
42 | |||
| addThirdPartySettingsSummary | |
0.00% |
0 / 9 |
|
0.00% |
0 / 12 |
|
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
42 | |||
| addComponentSettingsSummary | |
0.00% |
0 / 27 |
|
0.00% |
0 / 8 |
|
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\IslandPluginManagerInterface; |
| 11 | use Drupal\display_builder\IslandType; |
| 12 | use Drupal\display_builder\SlotSourceProxy; |
| 13 | use Drupal\display_builder\SourceWithSlotsInterface; |
| 14 | use Drupal\display_builder\ThirdPartySettingsInterface; |
| 15 | use Drupal\ui_patterns\SourceWithChoicesInterface; |
| 16 | use Symfony\Component\DependencyInjection\ContainerInterface; |
| 17 | |
| 18 | /** |
| 19 | * Layers island plugin implementation. |
| 20 | */ |
| 21 | #[Island( |
| 22 | id: 'layers', |
| 23 | label: new TranslatableMarkup('Layers'), |
| 24 | description: new TranslatableMarkup('Manage hierarchical layer view of elements without preview.'), |
| 25 | type: IslandType::View, |
| 26 | default_region: 'main', |
| 27 | icon: 'layers', |
| 28 | )] |
| 29 | class LayersPanel extends BuilderPanel { |
| 30 | |
| 31 | /** |
| 32 | * Proxy for slot source operations. |
| 33 | */ |
| 34 | protected SlotSourceProxy $slotSourceProxy; |
| 35 | |
| 36 | /** |
| 37 | * Island plugins manager. |
| 38 | */ |
| 39 | protected IslandPluginManagerInterface $islandManager; |
| 40 | |
| 41 | /** |
| 42 | * {@inheritdoc} |
| 43 | */ |
| 44 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static { |
| 45 | $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); |
| 46 | $instance->slotSourceProxy = $container->get('display_builder.slot_sources_proxy'); |
| 47 | $instance->islandManager = $container->get('plugin.manager.db_island'); |
| 48 | |
| 49 | return $instance; |
| 50 | } |
| 51 | |
| 52 | /** |
| 53 | * {@inheritdoc} |
| 54 | */ |
| 55 | public static function keyboardShortcuts(): array { |
| 56 | return [ |
| 57 | 'key' => 'y', |
| 58 | 'help' => t('Show the layer'), |
| 59 | ]; |
| 60 | } |
| 61 | |
| 62 | /** |
| 63 | * {@inheritdoc} |
| 64 | */ |
| 65 | public function build(InstanceInterface $builder, array $data = [], array $options = []): array { |
| 66 | $build = parent::build($builder, $data, $options); |
| 67 | |
| 68 | if (empty($build['#slots']['content'] ?? [])) { |
| 69 | // Load en empty component to have any assets with it. |
| 70 | $build['#slots']['content'] = [ |
| 71 | '#type' => 'component', |
| 72 | '#component' => 'display_builder:layer', |
| 73 | ]; |
| 74 | } |
| 75 | |
| 76 | return $build; |
| 77 | } |
| 78 | |
| 79 | /** |
| 80 | * {@inheritdoc} |
| 81 | */ |
| 82 | protected function buildSingleComponent(string $builder_id, string $instance_id, SourceWithSlotsInterface $source, array $data, int $index = 0): ?array { |
| 83 | $component_id = $source->getPluginID(); |
| 84 | $label = $source->label(); |
| 85 | |
| 86 | if ($source instanceof SourceWithChoicesInterface) { |
| 87 | $component_id = $source->getChoice($data['source']); |
| 88 | $label = $this->slotSourceProxy->getLabelWithSummary($data, [])['label']; |
| 89 | } |
| 90 | |
| 91 | $instance_id = $instance_id ?: $data['node_id']; |
| 92 | |
| 93 | if (!$instance_id || !$component_id) { |
| 94 | $params = [ |
| 95 | '@instance_id' => $instance_id ?? 'NULL', |
| 96 | '@component_id' => $component_id, |
| 97 | ]; |
| 98 | $this->logger->error('[LayersPanel::buildSingleComponent] missing component ID: @component_id or instance ID: @instance_id. <pre>' . \print_r($data, TRUE) . '</pre>', $params); |
| 99 | |
| 100 | return NULL; |
| 101 | } |
| 102 | |
| 103 | $slots = []; |
| 104 | |
| 105 | foreach ($source->getSlotDefinitions() as $slot_id => $definition) { |
| 106 | $dropzone = [ |
| 107 | '#type' => 'component', |
| 108 | '#component' => 'display_builder:dropzone', |
| 109 | '#props' => [ |
| 110 | 'title' => $definition['title'], |
| 111 | 'variant' => 'highlighted', |
| 112 | ], |
| 113 | '#attributes' => [ |
| 114 | // Required for JavaScript @see components/dropzone/dropzone.js. |
| 115 | 'data-db-id' => $builder_id, |
| 116 | // Slot is needed for contextual menu paste. |
| 117 | // @see assets/js/contextual_menu.js |
| 118 | 'data-slot-id' => $slot_id, |
| 119 | 'data-slot-title' => $definition['title'], |
| 120 | 'data-node-title' => $label, |
| 121 | 'data-instance-id' => $instance_id . '_' . $slot_id, |
| 122 | ], |
| 123 | ]; |
| 124 | |
| 125 | if ($sources = $source->getSlotValue($slot_id)) { |
| 126 | $dropzone['#slots']['content'] = $this->digFromSlot($builder_id, $sources); |
| 127 | } |
| 128 | $dropzone = $this->htmxEvents->onSlotDrop($dropzone, $builder_id, $this->getPluginID(), $instance_id, $slot_id); |
| 129 | $slots[] = [ |
| 130 | [ |
| 131 | '#plain_text' => $definition['title'], |
| 132 | ], |
| 133 | $dropzone, |
| 134 | ]; |
| 135 | } |
| 136 | |
| 137 | $build = [ |
| 138 | '#type' => 'component', |
| 139 | '#component' => 'display_builder:layer', |
| 140 | '#slots' => [ |
| 141 | 'title' => $label, |
| 142 | 'children' => $slots, |
| 143 | ], |
| 144 | // Required for the context menu label. |
| 145 | // @see assets/js/contextual_menu.js |
| 146 | '#attributes' => [ |
| 147 | 'data-node-title' => $label, |
| 148 | 'data-instance-id' => $instance_id, |
| 149 | ], |
| 150 | ]; |
| 151 | $build = $this->addThirdPartySettingsSummary($data, $build); |
| 152 | $build = $this->addComponentSettingsSummary($source, $build); |
| 153 | |
| 154 | return $this->htmxEvents->onInstanceClick($build, $builder_id, $instance_id, $source->label(), $index); |
| 155 | } |
| 156 | |
| 157 | /** |
| 158 | * {@inheritdoc} |
| 159 | */ |
| 160 | protected function buildSingleBlock(string $builder_id, string $instance_id, array $data, int $index = 0): array { |
| 161 | $label = $this->slotSourceProxy->getLabelWithSummary($data, $this->configuration['contexts'] ?? []); |
| 162 | |
| 163 | if (isset($data['source_id']) && $data['source_id'] === 'entity_field') { |
| 164 | $label['summary'] = (string) $this->t('Field: @label', ['@label' => $label['label']]); |
| 165 | } |
| 166 | |
| 167 | $build = [ |
| 168 | '#type' => 'component', |
| 169 | '#component' => 'display_builder:layer', |
| 170 | '#slots' => [ |
| 171 | 'title' => $label['summary'], |
| 172 | ], |
| 173 | ]; |
| 174 | |
| 175 | $instance_id = $instance_id ?: $data['node_id'] ?? NULL; |
| 176 | |
| 177 | if (!$instance_id) { |
| 178 | $this->logger->error('[LayersPanel::buildSingleBlock] missing instance ID. <pre>' . \print_r($data, TRUE) . '</pre>'); |
| 179 | |
| 180 | return $build; |
| 181 | } |
| 182 | |
| 183 | $build = $this->addThirdPartySettingsSummary($data, $build); |
| 184 | |
| 185 | // This label is used for contextual menu. |
| 186 | // @see assets/js/contextual_menu.js |
| 187 | $build['#attributes']['data-node-title'] = $label['summary']; |
| 188 | $build['#attributes']['data-slot-position'] = $index; |
| 189 | $build['#attributes']['data-instance-id'] = $instance_id; |
| 190 | |
| 191 | // Add data-node-type for easier identification of block types in JS, CSS or |
| 192 | // tests. |
| 193 | if (isset($data['source_id'])) { |
| 194 | $build['#attributes']['data-node-type'] = $data['source_id']; |
| 195 | } |
| 196 | |
| 197 | return $this->htmxEvents->onInstanceClick($build, $builder_id, $instance_id, $label['summary'], $index); |
| 198 | } |
| 199 | |
| 200 | /** |
| 201 | * Add third party settings summary to layer's info slot. |
| 202 | * |
| 203 | * @param array $data |
| 204 | * The node data. |
| 205 | * @param array $build |
| 206 | * The layer component renderable array. |
| 207 | * |
| 208 | * @return array |
| 209 | * The layer component renderable array. |
| 210 | */ |
| 211 | private function addThirdPartySettingsSummary(array $data, array $build): array { |
| 212 | if (!isset($data['third_party_settings'])) { |
| 213 | return $build; |
| 214 | } |
| 215 | |
| 216 | foreach ($data['third_party_settings'] as $provider => $settings) { |
| 217 | // In Display Builder, third_party_settings providers can be: |
| 218 | // - an island plugin ID (our 'normal' way) |
| 219 | // - a Drupal module name (the Drupal way, found in displays imported and |
| 220 | // converted, not leveraged by us for now but we may do it later). |
| 221 | // So, let's check the plugin ID exists before running logic. |
| 222 | if (!$this->islandManager->hasDefinition($provider)) { |
| 223 | continue; |
| 224 | } |
| 225 | $island = $this->islandManager->createInstance($provider, $settings); |
| 226 | |
| 227 | if ($island instanceof ThirdPartySettingsInterface && $summary = $island->getSummary()) { |
| 228 | $build['#slots']['info'] = \array_merge($build['#slots']['info'] ?? [], $summary); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | return $build; |
| 233 | } |
| 234 | |
| 235 | /** |
| 236 | * Add config settings summary to layer's info slot. |
| 237 | * |
| 238 | * @param \Drupal\display_builder\SourceWithSlotsInterface $source |
| 239 | * The source plugin. |
| 240 | * @param array $build |
| 241 | * The layer component renderable array. |
| 242 | * |
| 243 | * @return array |
| 244 | * The layer component renderable array. |
| 245 | */ |
| 246 | private function addComponentSettingsSummary(SourceWithSlotsInterface $source, array $build): array { |
| 247 | $items = []; |
| 248 | |
| 249 | foreach ($source->settingsSummary() as $item) { |
| 250 | if ($item !== NULL) { |
| 251 | $items[] = [ |
| 252 | '#type' => 'html_tag', |
| 253 | '#tag' => 'li', |
| 254 | '#value' => $item, |
| 255 | ]; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | if (empty($items)) { |
| 260 | return $build; |
| 261 | } |
| 262 | |
| 263 | $summary = [ |
| 264 | [ |
| 265 | '#type' => 'html_tag', |
| 266 | '#tag' => 'em', |
| 267 | '#value' => new TranslatableMarkup('Config'), |
| 268 | ], |
| 269 | [ |
| 270 | '#type' => 'html_tag', |
| 271 | '#tag' => 'ul', |
| 272 | '#attributes' => [ |
| 273 | 'class' => ['summary'], |
| 274 | ], |
| 275 | 0 => $items, |
| 276 | ], |
| 277 | ]; |
| 278 | |
| 279 | $build['#slots']['info'] = \array_merge($build['#slots']['info'] ?? [], $summary); |
| 280 | |
| 281 | return $build; |
| 282 | } |
| 283 | |
| 284 | } |
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.
| 246 | private function addComponentSettingsSummary(SourceWithSlotsInterface $source, array $build): array { |
| 247 | $items = []; |
| 248 | |
| 249 | foreach ($source->settingsSummary() as $item) { |
| 249 | foreach ($source->settingsSummary() as $item) { |
| 250 | if ($item !== NULL) { |
| 249 | foreach ($source->settingsSummary() as $item) { |
| 250 | if ($item !== NULL) { |
| 251 | $items[] = [ |
| 252 | '#type' => 'html_tag', |
| 249 | foreach ($source->settingsSummary() as $item) { |
| 249 | foreach ($source->settingsSummary() as $item) { |
| 250 | if ($item !== NULL) { |
| 251 | $items[] = [ |
| 252 | '#type' => 'html_tag', |
| 253 | '#tag' => 'li', |
| 254 | '#value' => $item, |
| 255 | ]; |
| 256 | } |
| 257 | } |
| 258 | |
| 259 | if (empty($items)) { |
| 260 | return $build; |
| 265 | '#type' => 'html_tag', |
| 266 | '#tag' => 'em', |
| 267 | '#value' => new TranslatableMarkup('Config'), |
| 268 | ], |
| 269 | [ |
| 270 | '#type' => 'html_tag', |
| 271 | '#tag' => 'ul', |
| 272 | '#attributes' => [ |
| 273 | 'class' => ['summary'], |
| 274 | ], |
| 275 | 0 => $items, |
| 276 | ], |
| 277 | ]; |
| 278 | |
| 279 | $build['#slots']['info'] = \array_merge($build['#slots']['info'] ?? [], $summary); |
| 280 | |
| 281 | return $build; |
| 282 | } |
| 211 | private function addThirdPartySettingsSummary(array $data, array $build): array { |
| 212 | if (!isset($data['third_party_settings'])) { |
| 213 | return $build; |
| 216 | foreach ($data['third_party_settings'] as $provider => $settings) { |
| 216 | foreach ($data['third_party_settings'] as $provider => $settings) { |
| 216 | foreach ($data['third_party_settings'] as $provider => $settings) { |
| 217 | // In Display Builder, third_party_settings providers can be: |
| 218 | // - an island plugin ID (our 'normal' way) |
| 219 | // - a Drupal module name (the Drupal way, found in displays imported and |
| 220 | // converted, not leveraged by us for now but we may do it later). |
| 221 | // So, let's check the plugin ID exists before running logic. |
| 222 | if (!$this->islandManager->hasDefinition($provider)) { |
| 223 | continue; |
| 225 | $island = $this->islandManager->createInstance($provider, $settings); |
| 226 | |
| 227 | if ($island instanceof ThirdPartySettingsInterface && $summary = $island->getSummary()) { |
| 227 | if ($island instanceof ThirdPartySettingsInterface && $summary = $island->getSummary()) { |
| 227 | if ($island instanceof ThirdPartySettingsInterface && $summary = $island->getSummary()) { |
| 216 | foreach ($data['third_party_settings'] as $provider => $settings) { |
| 217 | // In Display Builder, third_party_settings providers can be: |
| 218 | // - an island plugin ID (our 'normal' way) |
| 219 | // - a Drupal module name (the Drupal way, found in displays imported and |
| 220 | // converted, not leveraged by us for now but we may do it later). |
| 221 | // So, let's check the plugin ID exists before running logic. |
| 222 | if (!$this->islandManager->hasDefinition($provider)) { |
| 223 | continue; |
| 224 | } |
| 225 | $island = $this->islandManager->createInstance($provider, $settings); |
| 226 | |
| 227 | if ($island instanceof ThirdPartySettingsInterface && $summary = $island->getSummary()) { |
| 228 | $build['#slots']['info'] = \array_merge($build['#slots']['info'] ?? [], $summary); |
| 216 | foreach ($data['third_party_settings'] as $provider => $settings) { |
| 216 | foreach ($data['third_party_settings'] as $provider => $settings) { |
| 217 | // In Display Builder, third_party_settings providers can be: |
| 218 | // - an island plugin ID (our 'normal' way) |
| 219 | // - a Drupal module name (the Drupal way, found in displays imported and |
| 220 | // converted, not leveraged by us for now but we may do it later). |
| 221 | // So, let's check the plugin ID exists before running logic. |
| 222 | if (!$this->islandManager->hasDefinition($provider)) { |
| 223 | continue; |
| 224 | } |
| 225 | $island = $this->islandManager->createInstance($provider, $settings); |
| 226 | |
| 227 | if ($island instanceof ThirdPartySettingsInterface && $summary = $island->getSummary()) { |
| 228 | $build['#slots']['info'] = \array_merge($build['#slots']['info'] ?? [], $summary); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | return $build; |
| 233 | } |
| 65 | public function build(InstanceInterface $builder, array $data = [], array $options = []): array { |
| 66 | $build = parent::build($builder, $data, $options); |
| 67 | |
| 68 | if (empty($build['#slots']['content'] ?? [])) { |
| 70 | $build['#slots']['content'] = [ |
| 71 | '#type' => 'component', |
| 72 | '#component' => 'display_builder:layer', |
| 73 | ]; |
| 74 | } |
| 75 | |
| 76 | return $build; |
| 76 | return $build; |
| 77 | } |
| 160 | protected function buildSingleBlock(string $builder_id, string $instance_id, array $data, int $index = 0): array { |
| 161 | $label = $this->slotSourceProxy->getLabelWithSummary($data, $this->configuration['contexts'] ?? []); |
| 162 | |
| 163 | if (isset($data['source_id']) && $data['source_id'] === 'entity_field') { |
| 163 | if (isset($data['source_id']) && $data['source_id'] === 'entity_field') { |
| 163 | if (isset($data['source_id']) && $data['source_id'] === 'entity_field') { |
| 164 | $label['summary'] = (string) $this->t('Field: @label', ['@label' => $label['label']]); |
| 165 | } |
| 166 | |
| 167 | $build = [ |
| 168 | '#type' => 'component', |
| 168 | '#type' => 'component', |
| 169 | '#component' => 'display_builder:layer', |
| 170 | '#slots' => [ |
| 171 | 'title' => $label['summary'], |
| 172 | ], |
| 173 | ]; |
| 174 | |
| 175 | $instance_id = $instance_id ?: $data['node_id'] ?? NULL; |
| 176 | |
| 177 | if (!$instance_id) { |
| 178 | $this->logger->error('[LayersPanel::buildSingleBlock] missing instance ID. <pre>' . \print_r($data, TRUE) . '</pre>'); |
| 179 | |
| 180 | return $build; |
| 183 | $build = $this->addThirdPartySettingsSummary($data, $build); |
| 184 | |
| 185 | // This label is used for contextual menu. |
| 186 | // @see assets/js/contextual_menu.js |
| 187 | $build['#attributes']['data-node-title'] = $label['summary']; |
| 188 | $build['#attributes']['data-slot-position'] = $index; |
| 189 | $build['#attributes']['data-instance-id'] = $instance_id; |
| 190 | |
| 191 | // Add data-node-type for easier identification of block types in JS, CSS or |
| 192 | // tests. |
| 193 | if (isset($data['source_id'])) { |
| 194 | $build['#attributes']['data-node-type'] = $data['source_id']; |
| 195 | } |
| 196 | |
| 197 | return $this->htmxEvents->onInstanceClick($build, $builder_id, $instance_id, $label['summary'], $index); |
| 197 | return $this->htmxEvents->onInstanceClick($build, $builder_id, $instance_id, $label['summary'], $index); |
| 198 | } |
| 82 | protected function buildSingleComponent(string $builder_id, string $instance_id, SourceWithSlotsInterface $source, array $data, int $index = 0): ?array { |
| 83 | $component_id = $source->getPluginID(); |
| 84 | $label = $source->label(); |
| 85 | |
| 86 | if ($source instanceof SourceWithChoicesInterface) { |
| 87 | $component_id = $source->getChoice($data['source']); |
| 88 | $label = $this->slotSourceProxy->getLabelWithSummary($data, [])['label']; |
| 89 | } |
| 90 | |
| 91 | $instance_id = $instance_id ?: $data['node_id']; |
| 91 | $instance_id = $instance_id ?: $data['node_id']; |
| 92 | |
| 93 | if (!$instance_id || !$component_id) { |
| 93 | if (!$instance_id || !$component_id) { |
| 93 | if (!$instance_id || !$component_id) { |
| 95 | '@instance_id' => $instance_id ?? 'NULL', |
| 96 | '@component_id' => $component_id, |
| 97 | ]; |
| 98 | $this->logger->error('[LayersPanel::buildSingleComponent] missing component ID: @component_id or instance ID: @instance_id. <pre>' . \print_r($data, TRUE) . '</pre>', $params); |
| 99 | |
| 100 | return NULL; |
| 103 | $slots = []; |
| 104 | |
| 105 | foreach ($source->getSlotDefinitions() as $slot_id => $definition) { |
| 105 | foreach ($source->getSlotDefinitions() as $slot_id => $definition) { |
| 105 | foreach ($source->getSlotDefinitions() as $slot_id => $definition) { |
| 106 | $dropzone = [ |
| 107 | '#type' => 'component', |
| 108 | '#component' => 'display_builder:dropzone', |
| 109 | '#props' => [ |
| 110 | 'title' => $definition['title'], |
| 111 | 'variant' => 'highlighted', |
| 112 | ], |
| 113 | '#attributes' => [ |
| 114 | // Required for JavaScript @see components/dropzone/dropzone.js. |
| 115 | 'data-db-id' => $builder_id, |
| 116 | // Slot is needed for contextual menu paste. |
| 117 | // @see assets/js/contextual_menu.js |
| 118 | 'data-slot-id' => $slot_id, |
| 119 | 'data-slot-title' => $definition['title'], |
| 120 | 'data-node-title' => $label, |
| 121 | 'data-instance-id' => $instance_id . '_' . $slot_id, |
| 122 | ], |
| 123 | ]; |
| 124 | |
| 125 | if ($sources = $source->getSlotValue($slot_id)) { |
| 126 | $dropzone['#slots']['content'] = $this->digFromSlot($builder_id, $sources); |
| 127 | } |
| 128 | $dropzone = $this->htmxEvents->onSlotDrop($dropzone, $builder_id, $this->getPluginID(), $instance_id, $slot_id); |
| 105 | foreach ($source->getSlotDefinitions() as $slot_id => $definition) { |
| 106 | $dropzone = [ |
| 107 | '#type' => 'component', |
| 108 | '#component' => 'display_builder:dropzone', |
| 109 | '#props' => [ |
| 110 | 'title' => $definition['title'], |
| 111 | 'variant' => 'highlighted', |
| 112 | ], |
| 113 | '#attributes' => [ |
| 114 | // Required for JavaScript @see components/dropzone/dropzone.js. |
| 115 | 'data-db-id' => $builder_id, |
| 116 | // Slot is needed for contextual menu paste. |
| 117 | // @see assets/js/contextual_menu.js |
| 118 | 'data-slot-id' => $slot_id, |
| 119 | 'data-slot-title' => $definition['title'], |
| 120 | 'data-node-title' => $label, |
| 121 | 'data-instance-id' => $instance_id . '_' . $slot_id, |
| 122 | ], |
| 123 | ]; |
| 124 | |
| 125 | if ($sources = $source->getSlotValue($slot_id)) { |
| 126 | $dropzone['#slots']['content'] = $this->digFromSlot($builder_id, $sources); |
| 127 | } |
| 128 | $dropzone = $this->htmxEvents->onSlotDrop($dropzone, $builder_id, $this->getPluginID(), $instance_id, $slot_id); |
| 105 | foreach ($source->getSlotDefinitions() as $slot_id => $definition) { |
| 106 | $dropzone = [ |
| 107 | '#type' => 'component', |
| 108 | '#component' => 'display_builder:dropzone', |
| 109 | '#props' => [ |
| 110 | 'title' => $definition['title'], |
| 111 | 'variant' => 'highlighted', |
| 112 | ], |
| 113 | '#attributes' => [ |
| 114 | // Required for JavaScript @see components/dropzone/dropzone.js. |
| 115 | 'data-db-id' => $builder_id, |
| 116 | // Slot is needed for contextual menu paste. |
| 117 | // @see assets/js/contextual_menu.js |
| 118 | 'data-slot-id' => $slot_id, |
| 119 | 'data-slot-title' => $definition['title'], |
| 120 | 'data-node-title' => $label, |
| 121 | 'data-instance-id' => $instance_id . '_' . $slot_id, |
| 122 | ], |
| 123 | ]; |
| 124 | |
| 125 | if ($sources = $source->getSlotValue($slot_id)) { |
| 126 | $dropzone['#slots']['content'] = $this->digFromSlot($builder_id, $sources); |
| 127 | } |
| 128 | $dropzone = $this->htmxEvents->onSlotDrop($dropzone, $builder_id, $this->getPluginID(), $instance_id, $slot_id); |
| 129 | $slots[] = [ |
| 130 | [ |
| 131 | '#plain_text' => $definition['title'], |
| 132 | ], |
| 133 | $dropzone, |
| 134 | ]; |
| 135 | } |
| 136 | |
| 137 | $build = [ |
| 138 | '#type' => 'component', |
| 139 | '#component' => 'display_builder:layer', |
| 140 | '#slots' => [ |
| 141 | 'title' => $label, |
| 142 | 'children' => $slots, |
| 143 | ], |
| 144 | // Required for the context menu label. |
| 145 | // @see assets/js/contextual_menu.js |
| 146 | '#attributes' => [ |
| 147 | 'data-node-title' => $label, |
| 148 | 'data-instance-id' => $instance_id, |
| 149 | ], |
| 150 | ]; |
| 151 | $build = $this->addThirdPartySettingsSummary($data, $build); |
| 152 | $build = $this->addComponentSettingsSummary($source, $build); |
| 153 | |
| 154 | return $this->htmxEvents->onInstanceClick($build, $builder_id, $instance_id, $source->label(), $index); |
| 155 | } |
| 44 | public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition): static { |
| 45 | $instance = parent::create($container, $configuration, $plugin_id, $plugin_definition); |
| 46 | $instance->slotSourceProxy = $container->get('display_builder.slot_sources_proxy'); |
| 47 | $instance->islandManager = $container->get('plugin.manager.db_island'); |
| 48 | |
| 49 | return $instance; |
| 50 | } |
| 57 | 'key' => 'y', |
| 58 | 'help' => t('Show the layer'), |
| 59 | ]; |
| 60 | } |