Chris@0: themeManager = $theme_manager;
Chris@0: $this->formBuilder = $form_builder;
Chris@17: $this->messenger = $messenger;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
Chris@0: return new static(
Chris@0: $entity_type,
Chris@18: $container->get('entity_type.manager')->getStorage($entity_type->id()),
Chris@0: $container->get('theme.manager'),
Chris@17: $container->get('form_builder'),
Chris@17: $container->get('messenger')
Chris@0: );
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: *
Chris@0: * @param string|null $theme
Chris@0: * (optional) The theme to display the blocks for. If NULL, the current
Chris@0: * theme will be used.
Chris@0: * @param \Symfony\Component\HttpFoundation\Request $request
Chris@0: * The current request.
Chris@0: *
Chris@0: * @return array
Chris@0: * The block list as a renderable array.
Chris@0: */
Chris@0: public function render($theme = NULL, Request $request = NULL) {
Chris@0: $this->request = $request;
Chris@0: $this->theme = $theme;
Chris@0:
Chris@0: return $this->formBuilder->getForm($this);
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: public function getFormId() {
Chris@0: return 'block_admin_display_form';
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: public function buildForm(array $form, FormStateInterface $form_state) {
Chris@0: $form['#attached']['library'][] = 'core/drupal.tableheader';
Chris@0: $form['#attached']['library'][] = 'block/drupal.block';
Chris@0: $form['#attached']['library'][] = 'block/drupal.block.admin';
Chris@0: $form['#attributes']['class'][] = 'clearfix';
Chris@0:
Chris@0: // Build the form tree.
Chris@0: $form['blocks'] = $this->buildBlocksForm();
Chris@0:
Chris@0: $form['actions'] = [
Chris@0: '#tree' => FALSE,
Chris@0: '#type' => 'actions',
Chris@0: ];
Chris@0: $form['actions']['submit'] = [
Chris@0: '#type' => 'submit',
Chris@0: '#value' => $this->t('Save blocks'),
Chris@0: '#button_type' => 'primary',
Chris@0: ];
Chris@0:
Chris@0: return $form;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Builds the main "Blocks" portion of the form.
Chris@0: *
Chris@0: * @return array
Chris@0: */
Chris@0: protected function buildBlocksForm() {
Chris@0: // Build blocks first for each region.
Chris@0: $blocks = [];
Chris@0: $entities = $this->load();
Chris@0: /** @var \Drupal\block\BlockInterface[] $entities */
Chris@0: foreach ($entities as $entity_id => $entity) {
Chris@0: $definition = $entity->getPlugin()->getPluginDefinition();
Chris@0: $blocks[$entity->getRegion()][$entity_id] = [
Chris@0: 'label' => $entity->label(),
Chris@0: 'entity_id' => $entity_id,
Chris@0: 'weight' => $entity->getWeight(),
Chris@0: 'entity' => $entity,
Chris@0: 'category' => $definition['category'],
Chris@0: 'status' => $entity->status(),
Chris@0: ];
Chris@0: }
Chris@0:
Chris@0: $form = [
Chris@0: '#type' => 'table',
Chris@0: '#header' => [
Chris@0: $this->t('Block'),
Chris@0: $this->t('Category'),
Chris@0: $this->t('Region'),
Chris@0: $this->t('Weight'),
Chris@0: $this->t('Operations'),
Chris@0: ],
Chris@0: '#attributes' => [
Chris@0: 'id' => 'blocks',
Chris@0: ],
Chris@0: ];
Chris@0:
Chris@0: // Weights range from -delta to +delta, so delta should be at least half
Chris@0: // of the amount of blocks present. This makes sure all blocks in the same
Chris@0: // region get an unique weight.
Chris@0: $weight_delta = round(count($entities) / 2);
Chris@0:
Chris@0: $placement = FALSE;
Chris@0: if ($this->request->query->has('block-placement')) {
Chris@0: $placement = $this->request->query->get('block-placement');
Chris@0: $form['#attached']['drupalSettings']['blockPlacement'] = $placement;
Chris@17: // Remove the block placement from the current request so that it is not
Chris@17: // passed on to any redirect destinations.
Chris@17: $this->request->query->remove('block-placement');
Chris@0: }
Chris@0:
Chris@0: // Loop over each region and build blocks.
Chris@0: $regions = $this->systemRegionList($this->getThemeName(), REGIONS_VISIBLE);
Chris@0: foreach ($regions as $region => $title) {
Chris@0: $form['#tabledrag'][] = [
Chris@0: 'action' => 'match',
Chris@0: 'relationship' => 'sibling',
Chris@0: 'group' => 'block-region-select',
Chris@0: 'subgroup' => 'block-region-' . $region,
Chris@0: 'hidden' => FALSE,
Chris@0: ];
Chris@0: $form['#tabledrag'][] = [
Chris@0: 'action' => 'order',
Chris@0: 'relationship' => 'sibling',
Chris@0: 'group' => 'block-weight',
Chris@0: 'subgroup' => 'block-weight-' . $region,
Chris@0: ];
Chris@0:
Chris@0: $form['region-' . $region] = [
Chris@0: '#attributes' => [
Chris@0: 'class' => ['region-title', 'region-title-' . $region],
Chris@0: 'no_striping' => TRUE,
Chris@0: ],
Chris@0: ];
Chris@0: $form['region-' . $region]['title'] = [
Chris@0: '#theme_wrappers' => [
Chris@0: 'container' => [
Chris@0: '#attributes' => ['class' => 'region-title__action'],
Chris@17: ],
Chris@0: ],
Chris@0: '#prefix' => $title,
Chris@0: '#type' => 'link',
Chris@0: '#title' => $this->t('Place block in the %region region', ['%region' => $title]),
Chris@0: '#url' => Url::fromRoute('block.admin_library', ['theme' => $this->getThemeName()], ['query' => ['region' => $region]]),
Chris@0: '#wrapper_attributes' => [
Chris@0: 'colspan' => 5,
Chris@0: ],
Chris@0: '#attributes' => [
Chris@0: 'class' => ['use-ajax', 'button', 'button--small'],
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:
Chris@0: $form['region-' . $region . '-message'] = [
Chris@0: '#attributes' => [
Chris@0: 'class' => [
Chris@0: 'region-message',
Chris@0: 'region-' . $region . '-message',
Chris@0: empty($blocks[$region]) ? 'region-empty' : 'region-populated',
Chris@0: ],
Chris@0: ],
Chris@0: ];
Chris@0: $form['region-' . $region . '-message']['message'] = [
Chris@0: '#markup' => '' . $this->t('No blocks in this region') . '',
Chris@0: '#wrapper_attributes' => [
Chris@0: 'colspan' => 5,
Chris@0: ],
Chris@0: ];
Chris@0:
Chris@0: if (isset($blocks[$region])) {
Chris@0: foreach ($blocks[$region] as $info) {
Chris@0: $entity_id = $info['entity_id'];
Chris@0:
Chris@0: $form[$entity_id] = [
Chris@0: '#attributes' => [
Chris@0: 'class' => ['draggable'],
Chris@0: ],
Chris@0: ];
Chris@0: $form[$entity_id]['#attributes']['class'][] = $info['status'] ? 'block-enabled' : 'block-disabled';
Chris@0: if ($placement && $placement == Html::getClass($entity_id)) {
Chris@0: $form[$entity_id]['#attributes']['class'][] = 'color-success';
Chris@0: $form[$entity_id]['#attributes']['class'][] = 'js-block-placed';
Chris@0: }
Chris@0: $form[$entity_id]['info'] = [
Chris@0: '#plain_text' => $info['status'] ? $info['label'] : $this->t('@label (disabled)', ['@label' => $info['label']]),
Chris@0: '#wrapper_attributes' => [
Chris@0: 'class' => ['block'],
Chris@0: ],
Chris@0: ];
Chris@0: $form[$entity_id]['type'] = [
Chris@0: '#markup' => $info['category'],
Chris@0: ];
Chris@0: $form[$entity_id]['region-theme']['region'] = [
Chris@0: '#type' => 'select',
Chris@0: '#default_value' => $region,
Chris@0: '#required' => TRUE,
Chris@0: '#title' => $this->t('Region for @block block', ['@block' => $info['label']]),
Chris@0: '#title_display' => 'invisible',
Chris@0: '#options' => $regions,
Chris@0: '#attributes' => [
Chris@0: 'class' => ['block-region-select', 'block-region-' . $region],
Chris@0: ],
Chris@0: '#parents' => ['blocks', $entity_id, 'region'],
Chris@0: ];
Chris@0: $form[$entity_id]['region-theme']['theme'] = [
Chris@0: '#type' => 'hidden',
Chris@0: '#value' => $this->getThemeName(),
Chris@0: '#parents' => ['blocks', $entity_id, 'theme'],
Chris@0: ];
Chris@0: $form[$entity_id]['weight'] = [
Chris@0: '#type' => 'weight',
Chris@0: '#default_value' => $info['weight'],
Chris@0: '#delta' => $weight_delta,
Chris@0: '#title' => $this->t('Weight for @block block', ['@block' => $info['label']]),
Chris@0: '#title_display' => 'invisible',
Chris@0: '#attributes' => [
Chris@0: 'class' => ['block-weight', 'block-weight-' . $region],
Chris@0: ],
Chris@0: ];
Chris@0: $form[$entity_id]['operations'] = $this->buildOperations($info['entity']);
Chris@0: }
Chris@0: }
Chris@0: }
Chris@0:
Chris@0: // Do not allow disabling the main system content block when it is present.
Chris@0: if (isset($form['system_main']['region'])) {
Chris@0: $form['system_main']['region']['#required'] = TRUE;
Chris@0: }
Chris@0: return $form;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Gets the name of the theme used for this block listing.
Chris@0: *
Chris@0: * @return string
Chris@0: * The name of the theme.
Chris@0: */
Chris@0: protected function getThemeName() {
Chris@0: // If no theme was specified, use the current theme.
Chris@0: if (!$this->theme) {
Chris@0: $this->theme = $this->themeManager->getActiveTheme()->getName();
Chris@0: }
Chris@0: return $this->theme;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: protected function getEntityIds() {
Chris@0: return $this->getStorage()->getQuery()
Chris@0: ->condition('theme', $this->getThemeName())
Chris@0: ->sort($this->entityType->getKey('id'))
Chris@0: ->execute();
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: public function getDefaultOperations(EntityInterface $entity) {
Chris@0: $operations = parent::getDefaultOperations($entity);
Chris@0:
Chris@0: if (isset($operations['edit'])) {
Chris@0: $operations['edit']['title'] = $this->t('Configure');
Chris@0: }
Chris@0:
Chris@0: if (isset($operations['delete'])) {
Chris@0: $operations['delete']['title'] = $this->t('Remove');
Chris@0: }
Chris@0: return $operations;
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: public function validateForm(array &$form, FormStateInterface $form_state) {
Chris@0: // No validation.
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * {@inheritdoc}
Chris@0: */
Chris@0: public function submitForm(array &$form, FormStateInterface $form_state) {
Chris@0: $entities = $this->storage->loadMultiple(array_keys($form_state->getValue('blocks')));
Chris@0: /** @var \Drupal\block\BlockInterface[] $entities */
Chris@0: foreach ($entities as $entity_id => $entity) {
Chris@0: $entity_values = $form_state->getValue(['blocks', $entity_id]);
Chris@0: $entity->setWeight($entity_values['weight']);
Chris@0: $entity->setRegion($entity_values['region']);
Chris@0: $entity->save();
Chris@0: }
Chris@17: $this->messenger->addStatus($this->t('The block settings have been updated.'));
Chris@0: }
Chris@0:
Chris@0: /**
Chris@0: * Wraps system_region_list().
Chris@0: */
Chris@0: protected function systemRegionList($theme, $show = REGIONS_ALL) {
Chris@0: return system_region_list($theme, $show);
Chris@0: }
Chris@0:
Chris@0: }