3 namespace Drupal\settings_tray\Block;
5 use Drupal\block\BlockForm;
6 use Drupal\block\BlockInterface;
7 use Drupal\Component\Utility\Html;
8 use Drupal\Core\Ajax\AjaxResponse;
9 use Drupal\Core\Ajax\RedirectCommand;
10 use Drupal\Core\Ajax\ReplaceCommand;
11 use Drupal\Core\Block\BlockPluginInterface;
12 use Drupal\Core\Form\FormStateInterface;
13 use Drupal\Core\Plugin\PluginWithFormsInterface;
17 * Provides form for block instance forms when used in the off-canvas dialog.
19 * This form removes advanced sections of regular block form such as the
20 * visibility settings, machine ID and region.
24 class BlockEntitySettingTrayForm extends BlockForm {
27 * Provides a title callback to get the block's admin label.
29 * @param \Drupal\block\BlockInterface $block
32 * @return \Drupal\Core\StringTranslation\TranslatableMarkup
35 public function title(BlockInterface $block) {
36 // @todo Wrap "Configure " in <span class="visually-hidden"></span> once
37 // https://www.drupal.org/node/2359901 is fixed.
38 return $this->t('Configure @block', ['@block' => $block->getPlugin()->getPluginDefinition()['admin_label']]);
44 public function form(array $form, FormStateInterface $form_state) {
45 $form = parent::form($form, $form_state);
47 // Create link to full block form.
49 if ($destination = $this->getRequest()->query->get('destination')) {
50 $query['destination'] = $destination;
52 $form['advanced_link'] = [
54 '#title' => $this->t('Advanced block options'),
55 '#url' => $this->entity->toUrl('edit-form', ['query' => $query]),
59 // Remove the ID and region elements.
60 unset($form['id'], $form['region'], $form['settings']['admin_label']);
62 if (isset($form['settings']['label_display']) && isset($form['settings']['label'])) {
63 // Only show the label input if the label will be shown on the page.
64 $form['settings']['label_display']['#weight'] = -100;
65 $form['settings']['label']['#states']['visible'] = [
66 ':input[name="settings[label_display]"]' => ['checked' => TRUE],
69 // Relabel to "Block title" because on the front-end this may be confused
71 $form['settings']['label']['#title'] = $this->t("Block title");
72 $form['settings']['label_display']['#title'] = $this->t("Display block title");
80 protected function actions(array $form, FormStateInterface $form_state) {
81 $actions = parent::actions($form, $form_state);
82 $actions['submit']['#value'] = $this->t('Save @block', ['@block' => $this->entity->getPlugin()->getPluginDefinition()['admin_label']]);
83 $actions['delete']['#access'] = FALSE;
90 protected function buildVisibilityInterface(array $form, FormStateInterface $form_state) {
91 // Do not display the visibility.
98 protected function validateVisibility(array $form, FormStateInterface $form_state) {
99 // Intentionally empty.
105 protected function submitVisibility(array $form, FormStateInterface $form_state) {
106 // Intentionally empty.
112 protected function getPluginForm(BlockPluginInterface $block) {
113 if ($block instanceof PluginWithFormsInterface) {
114 return $this->pluginFormFactory->createInstance($block, 'settings_tray', 'configure');
122 public function buildForm(array $form, FormStateInterface $form_state) {
123 $form = parent::buildForm($form, $form_state);
124 $form['actions']['submit']['#ajax'] = [
125 'callback' => '::submitFormDialog',
127 $form['#attached']['library'][] = 'core/drupal.dialog.ajax';
129 // static::submitFormDialog() requires data-drupal-selector to be the same
130 // between the various Ajax requests. A bug in
131 // \Drupal\Core\Form\FormBuilder prevents that from happening unless
132 // $form['#id'] is also the same. Normally, #id is set to a unique HTML ID
133 // via Html::getUniqueId(), but here we bypass that in order to work around
134 // the data-drupal-selector bug. This is okay so long as we assume that this
135 // form only ever occurs once on a page.
136 // @todo Remove this workaround once https://www.drupal.org/node/2897377 is
138 $form['#id'] = Html::getId($form_state->getBuildInfo()['form_id']);
144 * Submit form dialog #ajax callback.
147 * An associative array containing the structure of the form.
148 * @param \Drupal\Core\Form\FormStateInterface $form_state
149 * The current state of the form.
151 * @return \Drupal\Core\Ajax\AjaxResponse
152 * An AJAX response that display validation error messages or redirects
155 * @todo Repalce this callback with generic trait in
156 * https://www.drupal.org/node/2896535.
158 public function submitFormDialog(array &$form, FormStateInterface $form_state) {
159 $response = new AjaxResponse();
160 if ($form_state->hasAnyErrors()) {
161 $form['status_messages'] = [
162 '#type' => 'status_messages',
165 $command = new ReplaceCommand('[data-drupal-selector="' . $form['#attributes']['data-drupal-selector'] . '"]', $form);
168 if ($redirect_url = $this->getRedirectUrl()) {
169 $command = new RedirectCommand($redirect_url->setAbsolute()->toString());
172 // Settings Tray always provides a destination.
173 throw new \Exception("No destination provided by Settings Tray form");
176 return $response->addCommand($command);
180 * Gets the form's redirect URL from 'destination' provide in the request.
182 * @return \Drupal\Core\Url|null
183 * The redirect URL or NULL if dialog should just be closed.
185 protected function getRedirectUrl() {
186 // \Drupal\Core\Routing\RedirectDestination::get() cannot be used directly
187 // because it will use <current> if 'destination' is not in the query
189 if ($this->getRequest()->query->has('destination') && $destination = $this->getRedirectDestination()->get()) {
190 return Url::fromUserInput('/' . $destination);