diff --git a/contacts.module b/contacts.module
index 675d5b8..7d1aabd 100644
--- a/contacts.module
+++ b/contacts.module
@@ -28,7 +28,10 @@ use Drupal\Core\Session\AccountInterface;
function contacts_theme() {
return [
'contacts_dash_tabs' => [
- 'variables' => ['tabs' => []],
+ 'variables' => [
+ 'tabs' => [],
+ 'manage_mode' => NULL,
+ ],
'template' => 'contacts-dash-tabs',
],
'contacts_dash_summary' => [
@@ -130,7 +133,40 @@ function template_preprocess_contacts_dash_tabs(array &$variables) {
],
];
- foreach ($variables['tabs'] as &$tab) {
+ foreach ($variables['tabs'] as $tab_id => &$tab) {
+ if ($variables['manage_mode']) {
+ // Add ui icons for manage mode.
+ $tab['ui'] = [
+ 'drag' => [
+ '#type' => 'open_iconic',
+ '#size' => '15',
+ '#icon' => 'move',
+ '#color' => 'transparent',
+ '#fill' => '#000',
+ '#attributes' => [
+ 'class' => ['contacts-ui-icon', 'icon-left', 'drag-handle'],
+ ],
+ ],
+ 'edit' => [
+ '#type' => 'open_iconic',
+ '#size' => '15',
+ '#icon' => 'cog',
+ '#color' => 'transparent',
+ '#fill' => '#5bc0de',
+ '#attributes' => [
+ 'class' => ['use-ajax', 'contacts-ui-icon', 'icon-left'],
+ 'data-ajax-url' => Url::fromRoute('contacts.tab.off_canvas_form',
+ [
+ 'tab' => $tab_id,
+ ]
+ )->toString(),
+ 'data-dialog-type' => 'dialog',
+ 'data-dialog-renderer' => 'off_canvas',
+ ],
+ ],
+
+ ];
+ }
$tab['attributes'] = !empty($tab['attributes']) ? new Attribute($tab['attributes']) : new Attribute();
$tab['link_attributes'] = !empty($tab['link_attributes']) ? new Attribute($tab['link_attributes']) : new Attribute();
}
diff --git a/contacts.routing.yml b/contacts.routing.yml
index b2a0f6b..7725c76 100644
--- a/contacts.routing.yml
+++ b/contacts.routing.yml
@@ -43,6 +43,13 @@ contacts.ajax.update_blocks:
requirements:
_permission: 'manage contacts dashboard'
+contacts.ajax.update_tabs:
+ path: '/admin/contacts/ajax/update-tabs'
+ defaults:
+ _controller: '\Drupal\contacts\Controller\DashboardController::ajaxUpdateTabs'
+ requirements:
+ _permission: 'manage contacts dashboard'
+
contacts.block.off_canvas_form:
path: '/admin/contacts/ajax/manage-off-canvas/{tab}/{block_name}'
defaults:
@@ -54,3 +61,15 @@ contacts.block.off_canvas_form:
type: entity:contact_tab
requirements:
_permission: 'administer blocks'
+
+contacts.tab.off_canvas_form:
+ path: '/admin/contacts/ajax/manage-off-canvas-tab/{tab}'
+ defaults:
+ _controller: '\Drupal\contacts\Controller\DashboardController::offCanvasTab'
+ _title: 'Edit tab'
+ options:
+ parameters:
+ tab:
+ type: entity:contact_tab
+ requirements:
+ _permission: 'administer blocks'
diff --git a/js/dashboard.manage.js b/js/dashboard.manage.js
index e45d171..1117aab 100644
--- a/js/dashboard.manage.js
+++ b/js/dashboard.manage.js
@@ -54,11 +54,11 @@
}
});
- var url = $(context).find('[data-contacts-manage-update-url]').data('contacts-manage-update-url'),
- postData = {
- regions: regions,
- tab: tab
- };
+ var url = $(context).find('[data-contacts-manage-update-url]').data('contacts-manage-update-url');
+ var postData = {
+ regions: regions,
+ tab: tab
+ };
$.ajax({
type: 'POST',
@@ -69,6 +69,37 @@
});
}
+ /**
+ * Update the Dashboard tabs after re-ordering.
+ *
+ * @param context
+ * The context of the tabs.
+ */
+ function updateDashboardTabs(context) {
+ var $dragArea = $(context).find('.contacts-ajax-tabs');
+
+ if ($dragArea.length === 0) {
+ return;
+ }
+
+ var tabs = $dragArea.sortable("toArray", {attribute: 'data-contacts-drag-tab-id'});
+
+ console.log(tabs);
+
+ var url = '/admin/contacts/ajax/update-tabs';
+ var postData = {
+ tabs: tabs
+ };
+
+ $.ajax({
+ type: 'POST',
+ url: url,
+ data: postData
+ }).done(function (data) {
+ console.log(data);
+ });
+ }
+
/**
* Find all dashboard blocks and set manage ajax links.
*/
@@ -123,7 +154,7 @@
/**
* Add sorting of dashboard blocks in manage mode.
*/
- Drupal.behaviors.contactsDashboardManageDrag = {
+ Drupal.behaviors.contactsDashboardManageDragBlocks = {
attach: function attach(context) {
var $dragAreas = $(context).find('.drag-area');
@@ -151,6 +182,34 @@
}
};
+ /**
+ * Add sorting of dashboard tabs in manage mode.
+ */
+ Drupal.behaviors.contactsDashboardManageDragTabs = {
+ attach: function attach(context) {
+
+ var $dragAreas = $(context).find('.contacts-ajax-tabs');
+
+ if ($dragAreas.length === 0) {
+ return;
+ }
+
+ $dragAreas.each(function () {
+ $(this).sortable({
+
+ placeholder: "nav-item nav-link tab-area-placeholder",
+ handle: '.drag-handle',
+ update: function update(event, ui) {
+ var itemRegion = ui.item.closest('.contacts-ajax-tabs');
+ if (event.target === itemRegion[0]) {
+ updateDashboardTabs(context);
+ }
+ }
+ });
+ });
+ }
+ };
+
$(document).on('drupalManageLinkAdded', function (event, data) {
Drupal.ajax.bindAjaxLinks(data.$el[0]);
});
diff --git a/src/Controller/AjaxHelperTrait.php b/src/Controller/AjaxHelperTrait.php
new file mode 100644
index 0000000..92633f9
--- /dev/null
+++ b/src/Controller/AjaxHelperTrait.php
@@ -0,0 +1,39 @@
+getRequestWrapperFormat(), [
+ 'drupal_ajax',
+ 'drupal_dialog',
+ 'drupal_dialog.off_canvas',
+ 'drupal_modal',
+ ]);
+ }
+
+ /**
+ * Gets the wrapper format of the current request.
+ *
+ * @string
+ * The wrapper format.
+ */
+ protected function getRequestWrapperFormat() {
+ return \Drupal::request()->get(MainContentViewSubscriber::WRAPPER_FORMAT);
+ }
+
+}
diff --git a/src/Controller/DashboardController.php b/src/Controller/DashboardController.php
index 677a94d..9832f1c 100644
--- a/src/Controller/DashboardController.php
+++ b/src/Controller/DashboardController.php
@@ -6,11 +6,13 @@
use Drupal\contacts\ContactsTabManager;
use Drupal\contacts\Entity\ContactTab;
use Drupal\contacts\Form\DashboardBlockConfigureForm;
+use Drupal\contacts\Form\DashboardTabConfigureForm;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\Core\Block\BlockManager;
use Drupal\Core\Controller\ControllerBase;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Layout\LayoutPluginManager;
use Drupal\Core\Path\PathValidatorInterface;
use Drupal\Core\Plugin\Context\Context;
use Drupal\Core\Plugin\Context\ContextDefinition;
@@ -29,6 +31,8 @@
*/
class DashboardController extends ControllerBase {
+ use AjaxHelperTrait;
+
/**
* The tab manager.
*
@@ -64,6 +68,13 @@ class DashboardController extends ControllerBase {
*/
protected $contextHandler;
+ /**
+ * The layout manager service.
+ *
+ * @var \Drupal\Core\Layout\LayoutPluginManager
+ */
+ protected $layoutManager;
+
/**
* Construct the dashboard controller.
*
@@ -81,8 +92,10 @@ class DashboardController extends ControllerBase {
* The context handler.
* @param \Drupal\Core\Form\FormBuilderInterface $form_builder
* The form builder service.
+ * @param \Drupal\Core\Layout\LayoutPluginManager $layout_manager
+ * The layout manager service.
*/
- public function __construct(ContactsTabManager $tab_manager, BlockManager $block_manager, StateInterface $state, RequestStack $request_stack, PathValidatorInterface $path_validator, ContextHandlerInterface $context_handler, FormBuilderInterface $form_builder) {
+ public function __construct(ContactsTabManager $tab_manager, BlockManager $block_manager, StateInterface $state, RequestStack $request_stack, PathValidatorInterface $path_validator, ContextHandlerInterface $context_handler, FormBuilderInterface $form_builder, LayoutPluginManager $layout_manager) {
$this->tabManager = $tab_manager;
$this->blockManager = $block_manager;
$this->state = $state;
@@ -90,6 +103,7 @@ public function __construct(ContactsTabManager $tab_manager, BlockManager $block
$this->pathValidator = $path_validator;
$this->contextHandler = $context_handler;
$this->formBuilder = $form_builder;
+ $this->layoutManager = $layout_manager;
}
/**
@@ -103,7 +117,8 @@ public static function create(ContainerInterface $container) {
$container->get('request_stack'),
$container->get('path.validator'),
$container->get('context.handler'),
- $container->get('form_builder')
+ $container->get('form_builder'),
+ $container->get('plugin.manager.core.layout')
);
}
@@ -126,6 +141,14 @@ public function ajaxTab(UserInterface $user, $subpage) {
'subpage' => $subpage,
]);
+ // Return as non-ajax.
+ if (!$this->isAjax()) {
+ return $this->redirect('page_manager.page_view_contacts_dashboard_contact', [
+ 'user' => $user->id(),
+ 'subpage' => $subpage,
+ ]);
+ }
+
$block = $this->blockManager->createInstance('tabs:contacts_dashboard');
// Build our contexts.
@@ -199,6 +222,47 @@ public function ajaxManageMode($manage_mode = NULL) {
return FALSE;
}
+ /**
+ * Adds AJAX command to response to show default tab offcanvas content.
+ *
+ * @param \Drupal\contacts\Entity\ContactTab $tab
+ * The tab to get content for.
+ *
+ * @return \Drupal\Core\Ajax\AjaxResponse
+ * The response commands.
+ */
+ public function ajaxManageModeRefresh(ContactTab $tab) {
+ $blocks = $this->tabManager->getBlocks($tab);
+
+ $layout = $tab->get('layout') ?: 'contacts_tab_content.stacked';
+ $layout = $this->layoutManager->createInstance($layout, []);
+
+ // @todo Once manage mode is decoupled from user context add tabs here.
+ $content['content'] = [
+ '#prefix' => '
',
+ '#suffix' => '
',
+ '#type' => 'contact_tab_content',
+ '#tab' => $tab,
+ '#layout' => $layout,
+ '#subpage' => $tab->getPath(),
+ '#blocks' => $blocks,
+ '#manage_mode' => TRUE,
+ '#attributes' => ['class' => ['dash-content']],
+ ];
+
+ $content['messages'] = [
+ '#type' => 'status_messages',
+ '#weight' => -99,
+ ];
+
+ // Create AJAX Response object.
+ $response = new AjaxResponse();
+ $response->addCommand(new HtmlCommand('#contacts-tabs-content', $content));
+
+ // Return ajax response.
+ return $response;
+ }
+
/**
* Provides a title callback to get the block's admin label.
*
@@ -236,6 +300,19 @@ public function offCanvasBlock(ContactTab $tab, $block_name) {
return $this->formBuilder->getForm(DashboardBlockConfigureForm::class, $tab, $block);
}
+ /**
+ * Renders the off Canvas configure form for a Dashboard block.
+ *
+ * @param \Drupal\contacts\Entity\ContactTab $tab
+ * The the tab entity that contains the block.
+ *
+ * @return array
+ * The renderable block config form.
+ */
+ public function offCanvasTab(ContactTab $tab) {
+ return $this->formBuilder->getForm(DashboardTabConfigureForm::class, $tab);
+ }
+
/**
* Update all block regions and positions in a tab.
*
@@ -282,4 +359,42 @@ public function ajaxUpdateBlocks() {
return $response;
}
+ /**
+ * Update the order of tabs after sorting.
+ *
+ * @return \Symfony\Component\HttpFoundation\Response
+ * The response.
+ */
+ public function ajaxUpdateTabs() {
+ $tabs = \Drupal::request()->request->get('tabs');
+
+ $json = [];
+ $previous = -101;
+ foreach (array_filter($tabs) as $tab) {
+ /* @var \Drupal\contacts\Entity\ContactTab $tab */
+ $tab = $this->entityTypeManager()->getStorage('contact_tab')->load($tab);
+ $current_weight = $tab->get('weight');
+
+ // Where possible preserve the existing tab weight.
+ if ($previous < $current_weight) {
+ $new = $current_weight;
+ }
+ else {
+ $new = $previous + 5;
+ }
+
+ $tab->set('weight', $new);
+ $tab->save();
+ $json[] = ['id' => $tab->id(), 'weight' => $new];
+ $previous = $new;
+ }
+
+ $response = new Response();
+ $response->setContent(json_encode($json));
+ $response->headers->set('Content-Type', 'application/json');
+ $response->setStatusCode(Response::HTTP_OK);
+
+ return $response;
+ }
+
}
diff --git a/src/Controller/DashboardRebuildTrait.php b/src/Controller/DashboardRebuildTrait.php
new file mode 100644
index 0000000..33f7b67
--- /dev/null
+++ b/src/Controller/DashboardRebuildTrait.php
@@ -0,0 +1,58 @@
+rebuildDashboard($tab);
+ $response->addCommand(new CloseDialogCommand('#drupal-off-canvas'));
+ return $response;
+ }
+
+ /**
+ * Rebuilds the layout.
+ *
+ * @param \Drupal\contacts\Entity\ContactTab $tab
+ * The section storage.
+ *
+ * @return \Drupal\Core\Ajax\AjaxResponse
+ * An AJAX response to either rebuild the layout and close the dialog, or
+ * reload the page.
+ */
+ protected function rebuildDashboard(ContactTab $tab) {
+ $this->dashboardContoller = $this->classResolver->getInstanceFromDefinition(DashboardController::class);
+ return $this->dashboardContoller->ajaxManageModeRefresh($tab);
+ }
+
+}
diff --git a/src/Element/ContactTabs.php b/src/Element/ContactTabs.php
index 748ca8b..169bb3b 100644
--- a/src/Element/ContactTabs.php
+++ b/src/Element/ContactTabs.php
@@ -57,13 +57,14 @@ public static function preRenderTabContent(array $element) {
'#theme' => 'contacts_dash_tabs',
'#weight' => -1,
'#tabs' => [],
+ '#manage_mode' => $element['#manage_mode'],
'#attached' => [
'library' => ['contacts/tabs'],
],
];
foreach ($element['#tabs'] as $tab_id => $tab) {
- $element['content']['#tabs'][$tab['path']] = [
+ $element['content']['#tabs'][$tab_id] = [
'text' => $tab['label'],
'link' => Url::fromRoute('page_manager.page_view_contacts_dashboard_contact', [
'user' => $element['#user']->id(),
@@ -73,22 +74,22 @@ public static function preRenderTabContent(array $element) {
// Swap links for AJAX request links.
if ($element['#ajax']) {
- $element['content']['#tabs'][$tab['path']]['link_attributes']['data-ajax-url'] = Url::fromRoute('contacts.ajax_subpage', [
+ $element['content']['#tabs'][$tab_id]['link_attributes']['data-ajax-url'] = Url::fromRoute('contacts.ajax_subpage', [
'user' => $element['#user']->id(),
'subpage' => $tab['path'],
])->toString();
- $element['content']['#tabs'][$tab['path']]['link_attributes']['class'][] = 'use-ajax';
- $element['content']['#tabs'][$tab['path']]['link_attributes']['data-ajax-progress'] = 'fullscreen';
+ $element['content']['#tabs'][$tab_id]['link_attributes']['class'][] = 'use-ajax';
+ $element['content']['#tabs'][$tab_id]['link_attributes']['data-ajax-progress'] = 'fullscreen';
}
// Add tab id to attributes.
- $element['content']['#tabs'][$tab['path']]['link_attributes']['data-contacts-tab-id'] = $tab_id;
- }
+ $element['content']['#tabs'][$tab_id]['attributes']['data-contacts-drag-tab-id'] = $tab_id;
- // Add active class to current tab.
- if (isset($element['content']['#tabs'][$element['#subpage']])) {
- $element['content']['#tabs'][$element['#subpage']]['attributes']['class'][] = 'is-active';
- $element['content']['#tabs'][$element['#subpage']]['link_attributes']['class'][] = 'is-active';
+ // Add active class to current tab.
+ if ($tab['path'] == $element['#subpage']) {
+ $element['content']['#tabs'][$tab_id]['attributes']['class'][] = 'is-active';
+ $element['content']['#tabs'][$tab_id]['link_attributes']['class'][] = 'is-active';
+ }
}
return $element;
diff --git a/src/Form/AjaxFormHelperTrait.php b/src/Form/AjaxFormHelperTrait.php
new file mode 100644
index 0000000..4a717c8
--- /dev/null
+++ b/src/Form/AjaxFormHelperTrait.php
@@ -0,0 +1,59 @@
+hasAnyErrors()) {
+ $form['status_messages'] = [
+ '#type' => 'status_messages',
+ '#weight' => -1000,
+ ];
+ $response = new AjaxResponse();
+ $response->addCommand(new ReplaceCommand('[data-drupal-selector="' . $form['#attributes']['data-drupal-selector'] . '"]', $form));
+ }
+ else {
+ $response = $this->successfulAjaxSubmit($form, $form_state);
+ }
+ return $response;
+ }
+
+ /**
+ * Allows the form to respond to a successful AJAX submission.
+ *
+ * @param array $form
+ * An associative array containing the structure of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ * The current state of the form.
+ *
+ * @return \Drupal\Core\Ajax\AjaxResponse
+ * An AJAX response.
+ */
+ abstract protected function successfulAjaxSubmit(array $form, FormStateInterface $form_state);
+
+}
diff --git a/src/Form/DashboardBlockConfigureForm.php b/src/Form/DashboardBlockConfigureForm.php
index 8b4608b..7214658 100644
--- a/src/Form/DashboardBlockConfigureForm.php
+++ b/src/Form/DashboardBlockConfigureForm.php
@@ -3,6 +3,8 @@
namespace Drupal\contacts\Form;
use Drupal\contacts\ContactsTabManager;
+use Drupal\contacts\Controller\DashboardRebuildTrait;
+use Drupal\Core\DependencyInjection\ClassResolverInterface;
use Drupal\Core\Entity\EntityTypeManager;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
@@ -14,6 +16,9 @@
*/
class DashboardBlockConfigureForm extends FormBase {
+ use AjaxFormHelperTrait;
+ use DashboardRebuildTrait;
+
/**
* The block plugin being configured.
*
@@ -56,10 +61,13 @@ class DashboardBlockConfigureForm extends FormBase {
* The entity type manager.
* @param \Drupal\contacts\ContactsTabManager $tab_manager
* The contacts tab manager.
+ * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
+ * The class resolver service.
*/
- public function __construct(EntityTypeManager $entity_type_manager, ContactsTabManager $tab_manager) {
+ public function __construct(EntityTypeManager $entity_type_manager, ContactsTabManager $tab_manager, ClassResolverInterface $class_resolver) {
$this->entityTypeManager = $entity_type_manager;
$this->tabManager = $tab_manager;
+ $this->classResolver = $class_resolver;
}
/**
@@ -68,7 +76,8 @@ public function __construct(EntityTypeManager $entity_type_manager, ContactsTabM
public static function create(ContainerInterface $container) {
return new static(
$container->get('entity_type.manager'),
- $container->get('contacts.tab_manager')
+ $container->get('contacts.tab_manager'),
+ $container->get('class_resolver')
);
}
@@ -104,18 +113,34 @@ public function buildForm(array $form, FormStateInterface $form_state) {
unset($form['settings']['context_mapping']);
}
- $form['submit'] = [
+ $form['actions'] = ['#type' => 'actions'];
+ $form['actions']['submit'] = [
'#type' => 'submit',
'#value' => 'Save',
+ '#button_type' => 'primary',
];
- $form['cancel'] = [
+ $form['actions']['cancel'] = [
'#type' => 'submit',
'#value' => 'Cancel',
- '#submit' => [[$this, 'cancelBlock']],
+ '#submit' => [],
+ '#limit_validation_errors' => [],
+ ];
+
+ $form['actions']['remove'] = [
+ '#type' => 'submit',
+ '#value' => 'Remove',
+ '#submit' => [[$this, 'removeBlock']],
'#limit_validation_errors' => [],
];
+ // Add ajax to actions.
+ if ($this->isAjax()) {
+ $form['actions']['submit']['#ajax']['callback'] = '::ajaxSubmit';
+ $form['actions']['cancel']['#ajax']['callback'] = '::ajaxSubmit';
+ $form['actions']['remove']['#ajax']['callback'] = '::ajaxSubmit';
+ }
+
return $form;
}
@@ -131,6 +156,11 @@ public function validateForm(array &$form, FormStateInterface $form_state) {
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
+ $trigger = $form_state->getTriggeringElement();
+ if ($trigger['#value'] == 'Cancel') {
+ return;
+ }
+
$sub_form_state = SubformState::createForSubform($form['settings'], $form, $form_state);
$this->block->submitConfigurationForm($form, $sub_form_state);
$this->tab->setBlock($this->blockName, $this->block->getConfiguration());
@@ -138,15 +168,20 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
}
/**
- * Form submission handler; removes block from tab.
- *
- * @param array $form
- * An associative array containing the structure of the form.
- * @param \Drupal\Core\Form\FormStateInterface $form_state
- * The current state of the form.
+ * {@inheritdoc}
+ */
+ public function removeBlock(array &$form, FormStateInterface $form_state) {
+ $blocks = $this->tab->getBlocks();
+ unset($blocks[$this->blockName]);
+ $this->tab->setBlocks($blocks);
+ $this->tab->save();
+ }
+
+ /**
+ * {@inheritdoc}
*/
- public function cancelBlock(array &$form, FormStateInterface $form_state) {
- // Do nothing.
+ protected function successfulAjaxSubmit(array $form, FormStateInterface $form_state) {
+ return $this->rebuildAndReturn($this->tab);
}
}
diff --git a/src/Form/DashboardTabConfigureForm.php b/src/Form/DashboardTabConfigureForm.php
new file mode 100644
index 0000000..96a48f4
--- /dev/null
+++ b/src/Form/DashboardTabConfigureForm.php
@@ -0,0 +1,163 @@
+entityTypeManager = $entity_type_manager;
+ $this->tabManager = $tab_manager;
+ $this->classResolver = $class_resolver;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container) {
+ return new static(
+ $container->get('entity_type.manager'),
+ $container->get('contacts.tab_manager'),
+ $container->get('class_resolver')
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getFormId() {
+ return "dashboard_tab_configure_form";
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildForm(array $form, FormStateInterface $form_state) {
+ $this->tab = $form_state->getBuildInfo()['args'][0];
+ $form['#tree'] = TRUE;
+
+ $form['label'] = [
+ '#type' => 'textfield',
+ '#title' => $this->t('Label'),
+ '#maxlength' => 255,
+ '#default_value' => $this->tab->label(),
+ '#description' => $this->t("Label for the tab."),
+ '#required' => TRUE,
+ ];
+
+ $form['actions'] = ['#type' => 'actions'];
+ $form['actions']['submit'] = [
+ '#type' => 'submit',
+ '#value' => 'Save',
+ '#button_type' => 'primary',
+ ];
+
+ $form['actions']['cancel'] = [
+ '#type' => 'submit',
+ '#value' => 'Cancel',
+ '#limit_validation_errors' => [],
+ ];
+
+ $form['actions']['remove'] = [
+ '#type' => 'submit',
+ '#value' => 'Remove',
+ '#name' => 'remove',
+ '#submit' => [[$this, 'removeTab']],
+ '#limit_validation_errors' => [],
+ ];
+
+ // Add ajax to actions.
+ if ($this->isAjax()) {
+ $form['actions']['submit']['#ajax']['callback'] = '::ajaxSubmit';
+ $form['actions']['cancel']['#ajax']['callback'] = '::ajaxSubmit';
+ $form['actions']['remove']['#ajax']['callback'] = '::ajaxSubmit';
+ }
+
+ $form['messages'] = [
+ '#type' => 'status_messages',
+ '#weight' => -99,
+ ];
+
+ return $form;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateForm(array &$form, FormStateInterface $form_state) {
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function submitForm(array &$form, FormStateInterface $form_state) {
+ \Drupal::entityTypeManager()
+ ->getFormObject('contact_tab', 'edit')
+ ->setEntity($this->tab)
+ ->buildEntity($form, $form_state)
+ ->save();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeTab(array &$form, FormStateInterface $form_state) {
+ $this->tab->delete();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function successfulAjaxSubmit(array $form, FormStateInterface $form_state) {
+ $trigger = $form_state->getTriggeringElement();
+ if ($trigger['#name'] == 'remove') {
+ $this->tab = $this->tabManager->getTab('summary');
+ }
+ return $this->rebuildAndReturn($this->tab);
+ }
+
+}
diff --git a/templates/contacts-dash-tabs.html.twig b/templates/contacts-dash-tabs.html.twig
index 1197635..e88a808 100644
--- a/templates/contacts-dash-tabs.html.twig
+++ b/templates/contacts-dash-tabs.html.twig
@@ -2,11 +2,12 @@
{% endif %}