Chris@0: blockManager = $block_manager; Chris@0: $this->routeMatch = $route_match; Chris@0: $this->localActionManager = $local_action_manager; Chris@0: $this->contextRepository = $context_repository; Chris@0: } Chris@0: Chris@0: /** Chris@0: * {@inheritdoc} Chris@0: */ Chris@0: public static function create(ContainerInterface $container) { Chris@0: return new static( Chris@0: $container->get('plugin.manager.block'), Chris@0: $container->get('context.repository'), Chris@0: $container->get('current_route_match'), Chris@0: $container->get('plugin.manager.menu.local_action') Chris@0: ); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Shows a list of blocks that can be added to a theme's layout. Chris@0: * Chris@0: * @param \Symfony\Component\HttpFoundation\Request $request Chris@0: * The current request. Chris@0: * @param string $theme Chris@0: * Theme key of the block list. Chris@0: * Chris@0: * @return array Chris@0: * A render array as expected by the renderer. Chris@0: */ Chris@0: public function listBlocks(Request $request, $theme) { Chris@0: // Since modals do not render any other part of the page, we need to render Chris@0: // them manually as part of this listing. Chris@0: if ($request->query->get(MainContentViewSubscriber::WRAPPER_FORMAT) === 'drupal_modal') { Chris@0: $build['local_actions'] = $this->buildLocalActions(); Chris@0: } Chris@0: Chris@0: $headers = [ Chris@0: ['data' => $this->t('Block')], Chris@0: ['data' => $this->t('Category')], Chris@0: ['data' => $this->t('Operations')], Chris@0: ]; Chris@0: Chris@17: $region = $request->query->get('region'); Chris@17: $weight = $request->query->get('weight'); Chris@17: Chris@0: // Only add blocks which work without any available context. Chris@17: $definitions = $this->blockManager->getFilteredDefinitions('block_ui', $this->contextRepository->getAvailableContexts(), [ Chris@17: 'theme' => $theme, Chris@17: 'region' => $region, Chris@17: ]); Chris@0: // Order by category, and then by admin label. Chris@0: $definitions = $this->blockManager->getSortedDefinitions($definitions); Chris@14: // Filter out definitions that are not intended to be placed by the UI. Chris@14: $definitions = array_filter($definitions, function (array $definition) { Chris@14: return empty($definition['_block_ui_hidden']); Chris@14: }); Chris@0: Chris@0: $rows = []; Chris@0: foreach ($definitions as $plugin_id => $plugin_definition) { Chris@0: $row = []; Chris@0: $row['title']['data'] = [ Chris@0: '#type' => 'inline_template', Chris@0: '#template' => '
{{ label }}
', Chris@0: '#context' => [ Chris@0: 'label' => $plugin_definition['admin_label'], Chris@0: ], Chris@0: ]; Chris@0: $row['category']['data'] = $plugin_definition['category']; Chris@0: $links['add'] = [ Chris@0: 'title' => $this->t('Place block'), Chris@0: 'url' => Url::fromRoute('block.admin_add', ['plugin_id' => $plugin_id, 'theme' => $theme]), Chris@0: 'attributes' => [ Chris@0: 'class' => ['use-ajax'], Chris@0: 'data-dialog-type' => 'modal', Chris@0: 'data-dialog-options' => Json::encode([ Chris@0: 'width' => 700, Chris@0: ]), Chris@0: ], Chris@0: ]; Chris@0: if ($region) { Chris@0: $links['add']['query']['region'] = $region; Chris@0: } Chris@0: if (isset($weight)) { Chris@0: $links['add']['query']['weight'] = $weight; Chris@0: } Chris@0: $row['operations']['data'] = [ Chris@0: '#type' => 'operations', Chris@0: '#links' => $links, Chris@0: ]; Chris@0: $rows[] = $row; Chris@0: } Chris@0: Chris@0: $build['#attached']['library'][] = 'block/drupal.block.admin'; Chris@0: Chris@0: $build['filter'] = [ Chris@0: '#type' => 'search', Chris@0: '#title' => $this->t('Filter'), Chris@0: '#title_display' => 'invisible', Chris@0: '#size' => 30, Chris@0: '#placeholder' => $this->t('Filter by block name'), Chris@0: '#attributes' => [ Chris@0: 'class' => ['block-filter-text'], Chris@0: 'data-element' => '.block-add-table', Chris@0: 'title' => $this->t('Enter a part of the block name to filter by.'), Chris@0: ], Chris@0: ]; Chris@0: Chris@0: $build['blocks'] = [ Chris@0: '#type' => 'table', Chris@0: '#header' => $headers, Chris@0: '#rows' => $rows, Chris@0: '#empty' => $this->t('No blocks available.'), Chris@0: '#attributes' => [ Chris@0: 'class' => ['block-add-table'], Chris@0: ], Chris@0: ]; Chris@0: Chris@0: return $build; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Builds the local actions for this listing. Chris@0: * Chris@0: * @return array Chris@0: * An array of local actions for this listing. Chris@0: */ Chris@0: protected function buildLocalActions() { Chris@0: $build = $this->localActionManager->getActionsForRoute($this->routeMatch->getRouteName()); Chris@0: // Without this workaround, the action links will be rendered as
  • with Chris@0: // no wrapping