Chris@14
|
1 <?php
|
Chris@14
|
2
|
Chris@14
|
3 namespace Drupal\layout_builder\Controller;
|
Chris@14
|
4
|
Chris@17
|
5 use Drupal\Core\Ajax\AjaxHelperTrait;
|
Chris@14
|
6 use Drupal\Core\Block\BlockManagerInterface;
|
Chris@14
|
7 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
|
Chris@17
|
8 use Drupal\Core\Entity\EntityTypeManagerInterface;
|
Chris@18
|
9 use Drupal\Core\Session\AccountInterface;
|
Chris@17
|
10 use Drupal\Core\StringTranslation\StringTranslationTrait;
|
Chris@14
|
11 use Drupal\Core\Url;
|
Chris@14
|
12 use Drupal\layout_builder\Context\LayoutBuilderContextTrait;
|
Chris@18
|
13 use Drupal\layout_builder\LayoutBuilderHighlightTrait;
|
Chris@14
|
14 use Drupal\layout_builder\SectionStorageInterface;
|
Chris@14
|
15 use Symfony\Component\DependencyInjection\ContainerInterface;
|
Chris@14
|
16
|
Chris@14
|
17 /**
|
Chris@14
|
18 * Defines a controller to choose a new block.
|
Chris@14
|
19 *
|
Chris@14
|
20 * @internal
|
Chris@18
|
21 * Controller classes are internal.
|
Chris@14
|
22 */
|
Chris@14
|
23 class ChooseBlockController implements ContainerInjectionInterface {
|
Chris@14
|
24
|
Chris@14
|
25 use AjaxHelperTrait;
|
Chris@14
|
26 use LayoutBuilderContextTrait;
|
Chris@18
|
27 use LayoutBuilderHighlightTrait;
|
Chris@17
|
28 use StringTranslationTrait;
|
Chris@14
|
29
|
Chris@14
|
30 /**
|
Chris@14
|
31 * The block manager.
|
Chris@14
|
32 *
|
Chris@14
|
33 * @var \Drupal\Core\Block\BlockManagerInterface
|
Chris@14
|
34 */
|
Chris@14
|
35 protected $blockManager;
|
Chris@14
|
36
|
Chris@14
|
37 /**
|
Chris@17
|
38 * The entity type manager.
|
Chris@17
|
39 *
|
Chris@17
|
40 * @var \Drupal\Core\Entity\EntityTypeManagerInterface
|
Chris@17
|
41 */
|
Chris@17
|
42 protected $entityTypeManager;
|
Chris@17
|
43
|
Chris@17
|
44 /**
|
Chris@18
|
45 * The current user.
|
Chris@18
|
46 *
|
Chris@18
|
47 * @var \Drupal\Core\Session\AccountInterface
|
Chris@18
|
48 */
|
Chris@18
|
49 protected $currentUser;
|
Chris@18
|
50
|
Chris@18
|
51 /**
|
Chris@14
|
52 * ChooseBlockController constructor.
|
Chris@14
|
53 *
|
Chris@14
|
54 * @param \Drupal\Core\Block\BlockManagerInterface $block_manager
|
Chris@14
|
55 * The block manager.
|
Chris@17
|
56 * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
|
Chris@17
|
57 * The entity type manager.
|
Chris@18
|
58 * @param \Drupal\Core\Session\AccountInterface $current_user
|
Chris@18
|
59 * The current user.
|
Chris@14
|
60 */
|
Chris@18
|
61 public function __construct(BlockManagerInterface $block_manager, EntityTypeManagerInterface $entity_type_manager, AccountInterface $current_user = NULL) {
|
Chris@14
|
62 $this->blockManager = $block_manager;
|
Chris@17
|
63 $this->entityTypeManager = $entity_type_manager;
|
Chris@18
|
64 if (!$current_user) {
|
Chris@18
|
65 @trigger_error('The current_user service must be passed to ChooseBlockController::__construct(), it is required before Drupal 9.0.0.', E_USER_DEPRECATED);
|
Chris@18
|
66 $current_user = \Drupal::currentUser();
|
Chris@18
|
67 }
|
Chris@18
|
68 $this->currentUser = $current_user;
|
Chris@14
|
69 }
|
Chris@14
|
70
|
Chris@14
|
71 /**
|
Chris@14
|
72 * {@inheritdoc}
|
Chris@14
|
73 */
|
Chris@14
|
74 public static function create(ContainerInterface $container) {
|
Chris@14
|
75 return new static(
|
Chris@17
|
76 $container->get('plugin.manager.block'),
|
Chris@18
|
77 $container->get('entity_type.manager'),
|
Chris@18
|
78 $container->get('current_user')
|
Chris@14
|
79 );
|
Chris@14
|
80 }
|
Chris@14
|
81
|
Chris@14
|
82 /**
|
Chris@14
|
83 * Provides the UI for choosing a new block.
|
Chris@14
|
84 *
|
Chris@14
|
85 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
|
Chris@14
|
86 * The section storage.
|
Chris@14
|
87 * @param int $delta
|
Chris@14
|
88 * The delta of the section to splice.
|
Chris@14
|
89 * @param string $region
|
Chris@14
|
90 * The region the block is going in.
|
Chris@14
|
91 *
|
Chris@14
|
92 * @return array
|
Chris@14
|
93 * A render array.
|
Chris@14
|
94 */
|
Chris@14
|
95 public function build(SectionStorageInterface $section_storage, $delta, $region) {
|
Chris@17
|
96 if ($this->entityTypeManager->hasDefinition('block_content_type') && $types = $this->entityTypeManager->getStorage('block_content_type')->loadMultiple()) {
|
Chris@17
|
97 if (count($types) === 1) {
|
Chris@17
|
98 $type = reset($types);
|
Chris@17
|
99 $plugin_id = 'inline_block:' . $type->id();
|
Chris@17
|
100 if ($this->blockManager->hasDefinition($plugin_id)) {
|
Chris@17
|
101 $url = Url::fromRoute('layout_builder.add_block', [
|
Chris@17
|
102 'section_storage_type' => $section_storage->getStorageType(),
|
Chris@17
|
103 'section_storage' => $section_storage->getStorageId(),
|
Chris@17
|
104 'delta' => $delta,
|
Chris@17
|
105 'region' => $region,
|
Chris@17
|
106 'plugin_id' => $plugin_id,
|
Chris@17
|
107 ]);
|
Chris@17
|
108 }
|
Chris@17
|
109 }
|
Chris@17
|
110 else {
|
Chris@17
|
111 $url = Url::fromRoute('layout_builder.choose_inline_block', [
|
Chris@17
|
112 'section_storage_type' => $section_storage->getStorageType(),
|
Chris@17
|
113 'section_storage' => $section_storage->getStorageId(),
|
Chris@17
|
114 'delta' => $delta,
|
Chris@17
|
115 'region' => $region,
|
Chris@17
|
116 ]);
|
Chris@17
|
117 }
|
Chris@17
|
118 if (isset($url)) {
|
Chris@17
|
119 $build['add_block'] = [
|
Chris@17
|
120 '#type' => 'link',
|
Chris@17
|
121 '#url' => $url,
|
Chris@17
|
122 '#title' => $this->t('Create @entity_type', [
|
Chris@17
|
123 '@entity_type' => $this->entityTypeManager->getDefinition('block_content')->getSingularLabel(),
|
Chris@17
|
124 ]),
|
Chris@17
|
125 '#attributes' => $this->getAjaxAttributes(),
|
Chris@18
|
126 '#access' => $this->currentUser->hasPermission('create and edit custom blocks'),
|
Chris@17
|
127 ];
|
Chris@17
|
128 $build['add_block']['#attributes']['class'][] = 'inline-block-create-button';
|
Chris@17
|
129 }
|
Chris@17
|
130 }
|
Chris@14
|
131
|
Chris@18
|
132 $build['filter'] = [
|
Chris@18
|
133 '#type' => 'search',
|
Chris@18
|
134 '#title' => $this->t('Filter by block name'),
|
Chris@18
|
135 '#title_display' => 'invisible',
|
Chris@18
|
136 '#size' => 30,
|
Chris@18
|
137 '#placeholder' => $this->t('Filter by block name'),
|
Chris@18
|
138 '#attributes' => [
|
Chris@18
|
139 'class' => ['js-layout-builder-filter'],
|
Chris@18
|
140 'title' => $this->t('Enter a part of the block name to filter by.'),
|
Chris@18
|
141 ],
|
Chris@18
|
142 ];
|
Chris@18
|
143
|
Chris@17
|
144 $block_categories['#type'] = 'container';
|
Chris@17
|
145 $block_categories['#attributes']['class'][] = 'block-categories';
|
Chris@18
|
146 $block_categories['#attributes']['class'][] = 'js-layout-builder-categories';
|
Chris@18
|
147 $block_categories['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockAddHighlightId($delta, $region);
|
Chris@17
|
148
|
Chris@17
|
149 // @todo Explicitly cast delta to an integer, remove this in
|
Chris@17
|
150 // https://www.drupal.org/project/drupal/issues/2984509.
|
Chris@17
|
151 $delta = (int) $delta;
|
Chris@17
|
152
|
Chris@17
|
153 $definitions = $this->blockManager->getFilteredDefinitions('layout_builder', $this->getAvailableContexts($section_storage), [
|
Chris@17
|
154 'section_storage' => $section_storage,
|
Chris@17
|
155 'delta' => $delta,
|
Chris@17
|
156 'region' => $region,
|
Chris@17
|
157 ]);
|
Chris@17
|
158 $grouped_definitions = $this->blockManager->getGroupedDefinitions($definitions);
|
Chris@17
|
159 foreach ($grouped_definitions as $category => $blocks) {
|
Chris@17
|
160 $block_categories[$category]['#type'] = 'details';
|
Chris@18
|
161 $block_categories[$category]['#attributes']['class'][] = 'js-layout-builder-category';
|
Chris@17
|
162 $block_categories[$category]['#open'] = TRUE;
|
Chris@17
|
163 $block_categories[$category]['#title'] = $category;
|
Chris@17
|
164 $block_categories[$category]['links'] = $this->getBlockLinks($section_storage, $delta, $region, $blocks);
|
Chris@17
|
165 }
|
Chris@17
|
166 $build['block_categories'] = $block_categories;
|
Chris@17
|
167 return $build;
|
Chris@17
|
168 }
|
Chris@17
|
169
|
Chris@17
|
170 /**
|
Chris@17
|
171 * Provides the UI for choosing a new inline block.
|
Chris@17
|
172 *
|
Chris@17
|
173 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
|
Chris@17
|
174 * The section storage.
|
Chris@17
|
175 * @param int $delta
|
Chris@17
|
176 * The delta of the section to splice.
|
Chris@17
|
177 * @param string $region
|
Chris@17
|
178 * The region the block is going in.
|
Chris@17
|
179 *
|
Chris@17
|
180 * @return array
|
Chris@17
|
181 * A render array.
|
Chris@17
|
182 */
|
Chris@17
|
183 public function inlineBlockList(SectionStorageInterface $section_storage, $delta, $region) {
|
Chris@17
|
184 $definitions = $this->blockManager->getFilteredDefinitions('layout_builder', $this->getAvailableContexts($section_storage), [
|
Chris@17
|
185 'section_storage' => $section_storage,
|
Chris@17
|
186 'region' => $region,
|
Chris@17
|
187 'list' => 'inline_blocks',
|
Chris@17
|
188 ]);
|
Chris@17
|
189 $blocks = $this->blockManager->getGroupedDefinitions($definitions);
|
Chris@17
|
190 $build = [];
|
Chris@18
|
191 $inline_blocks_category = (string) $this->t('Inline blocks');
|
Chris@18
|
192 if (isset($blocks[$inline_blocks_category])) {
|
Chris@18
|
193 $build['links'] = $this->getBlockLinks($section_storage, $delta, $region, $blocks[$inline_blocks_category]);
|
Chris@17
|
194 $build['links']['#attributes']['class'][] = 'inline-block-list';
|
Chris@17
|
195 foreach ($build['links']['#links'] as &$link) {
|
Chris@17
|
196 $link['attributes']['class'][] = 'inline-block-list__item';
|
Chris@17
|
197 }
|
Chris@17
|
198 $build['back_button'] = [
|
Chris@17
|
199 '#type' => 'link',
|
Chris@17
|
200 '#url' => Url::fromRoute('layout_builder.choose_block',
|
Chris@17
|
201 [
|
Chris@17
|
202 'section_storage_type' => $section_storage->getStorageType(),
|
Chris@17
|
203 'section_storage' => $section_storage->getStorageId(),
|
Chris@17
|
204 'delta' => $delta,
|
Chris@17
|
205 'region' => $region,
|
Chris@17
|
206 ]
|
Chris@17
|
207 ),
|
Chris@17
|
208 '#title' => $this->t('Back'),
|
Chris@17
|
209 '#attributes' => $this->getAjaxAttributes(),
|
Chris@14
|
210 ];
|
Chris@14
|
211 }
|
Chris@18
|
212 $build['links']['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockAddHighlightId($delta, $region);
|
Chris@14
|
213 return $build;
|
Chris@14
|
214 }
|
Chris@14
|
215
|
Chris@17
|
216 /**
|
Chris@17
|
217 * Gets a render array of block links.
|
Chris@17
|
218 *
|
Chris@17
|
219 * @param \Drupal\layout_builder\SectionStorageInterface $section_storage
|
Chris@17
|
220 * The section storage.
|
Chris@17
|
221 * @param int $delta
|
Chris@17
|
222 * The delta of the section to splice.
|
Chris@17
|
223 * @param string $region
|
Chris@17
|
224 * The region the block is going in.
|
Chris@17
|
225 * @param array $blocks
|
Chris@17
|
226 * The information for each block.
|
Chris@17
|
227 *
|
Chris@17
|
228 * @return array
|
Chris@17
|
229 * The block links render array.
|
Chris@17
|
230 */
|
Chris@17
|
231 protected function getBlockLinks(SectionStorageInterface $section_storage, $delta, $region, array $blocks) {
|
Chris@17
|
232 $links = [];
|
Chris@17
|
233 foreach ($blocks as $block_id => $block) {
|
Chris@18
|
234 $attributes = $this->getAjaxAttributes();
|
Chris@18
|
235 $attributes['class'][] = 'js-layout-builder-block-link';
|
Chris@17
|
236 $link = [
|
Chris@17
|
237 'title' => $block['admin_label'],
|
Chris@17
|
238 'url' => Url::fromRoute('layout_builder.add_block',
|
Chris@17
|
239 [
|
Chris@17
|
240 'section_storage_type' => $section_storage->getStorageType(),
|
Chris@17
|
241 'section_storage' => $section_storage->getStorageId(),
|
Chris@17
|
242 'delta' => $delta,
|
Chris@17
|
243 'region' => $region,
|
Chris@17
|
244 'plugin_id' => $block_id,
|
Chris@17
|
245 ]
|
Chris@17
|
246 ),
|
Chris@18
|
247 'attributes' => $attributes,
|
Chris@17
|
248 ];
|
Chris@17
|
249
|
Chris@17
|
250 $links[] = $link;
|
Chris@17
|
251 }
|
Chris@17
|
252 return [
|
Chris@17
|
253 '#theme' => 'links',
|
Chris@17
|
254 '#links' => $links,
|
Chris@17
|
255 ];
|
Chris@17
|
256 }
|
Chris@17
|
257
|
Chris@17
|
258 /**
|
Chris@17
|
259 * Get dialog attributes if an ajax request.
|
Chris@17
|
260 *
|
Chris@17
|
261 * @return array
|
Chris@17
|
262 * The attributes array.
|
Chris@17
|
263 */
|
Chris@17
|
264 protected function getAjaxAttributes() {
|
Chris@17
|
265 if ($this->isAjax()) {
|
Chris@17
|
266 return [
|
Chris@17
|
267 'class' => ['use-ajax'],
|
Chris@17
|
268 'data-dialog-type' => 'dialog',
|
Chris@17
|
269 'data-dialog-renderer' => 'off_canvas',
|
Chris@17
|
270 ];
|
Chris@17
|
271 }
|
Chris@17
|
272 return [];
|
Chris@17
|
273 }
|
Chris@17
|
274
|
Chris@14
|
275 }
|