diff --git a/client/src/controllers/SessionController.test.js b/client/src/controllers/SessionController.test.js
index b0eaca01f4..9b82737487 100644
--- a/client/src/controllers/SessionController.test.js
+++ b/client/src/controllers/SessionController.test.js
@@ -238,9 +238,10 @@ describe('SessionController', () => {
workflowActionButton.addEventListener('click', handleWorkflowAction, {
capture: true,
});
- document.addEventListener('w-dialog:shown', handleDialogShow);
- document.addEventListener('w-dialog:hidden', handleDialogHidden);
- document.addEventListener('w-dialog:confirmed', handleDialogConfirmed);
+ const dialog = document.getElementById('w-overwrite-changes-dialog');
+ dialog.addEventListener('w-dialog:shown', handleDialogShow);
+ dialog.addEventListener('w-dialog:hidden', handleDialogHidden);
+ dialog.addEventListener('w-dialog:confirmed', handleDialogConfirmed);
});
afterEach(() => {
@@ -410,6 +411,91 @@ describe('SessionController', () => {
expect(dialog.getAttribute('aria-hidden')).toBeNull();
expect(confirmButton.textContent).toEqual('Approve');
});
+
+ it("should hide the submit button's dialog when it shows the confirmation dialog and show it again afterwards", async () => {
+ const confirmButton = document.getElementById('confirm');
+ // Mark the confirm button as DialogController's confirm target
+ confirmButton.setAttribute('data-w-dialog-target', 'confirm');
+
+ const otherDialog = document.createElement('div');
+ otherDialog.id = 'w-schedule-publishing-dialog';
+ otherDialog.setAttribute('aria-hidden', 'true');
+ otherDialog.setAttribute('data-controller', 'w-dialog');
+ otherDialog.setAttribute(
+ 'data-action',
+ 'w-dialog:hide->w-dialog#hide w-dialog:show->w-dialog#show',
+ );
+ otherDialog.innerHTML = /* html */ `
+
+ `;
+
+ const otherDialogTrigger = document.createElement('button');
+ otherDialogTrigger.type = 'button';
+ otherDialogTrigger.setAttribute(
+ 'data-a11y-dialog-show',
+ 'w-schedule-publishing-dialog',
+ );
+ otherDialogTrigger.innerHTML = 'Set schedule';
+
+ form.appendChild(otherDialog);
+ form.appendChild(otherDialogTrigger);
+
+ // Reconnect the DialogController so the submit button in the
+ // schedule publishing dialog works
+ const dialog = document.querySelector('#w-overwrite-changes-dialog');
+ dialog.removeAttribute('data-controller');
+ await Promise.resolve();
+ dialog.setAttribute('data-controller', 'w-dialog');
+ await Promise.resolve();
+
+ expect(handleDialogShow).not.toHaveBeenCalled();
+
+ // Show the schedule publishing dialog
+ otherDialogTrigger.click();
+ expect(otherDialog.getAttribute('aria-hidden')).toBeNull();
+
+ // Should not trigger the confirmation dialog yet
+ expect(handleDialogShow).not.toHaveBeenCalled();
+
+ const scheduleSubmitButton = otherDialog.querySelector(
+ 'button[type="submit"]',
+ );
+ scheduleSubmitButton.click();
+ await Promise.resolve();
+
+ // Should trigger the confirmation dialog
+ expect(handleSubmit).not.toHaveBeenCalled();
+ expect(handleWorkflowAction).not.toHaveBeenCalled();
+ expect(handleDialogShow).toHaveBeenCalled();
+ expect(dialog.getAttribute('aria-hidden')).toBeNull();
+ expect(confirmButton.textContent).toEqual('Save schedule');
+
+ // Should hide the schedule publishing dialog
+ expect(otherDialog.getAttribute('aria-hidden')).toEqual('true');
+
+ // Confirm the dialog
+ confirmButton.click();
+ await Promise.resolve();
+
+ // Should hide the confirmation dialog and continue the action
+ expect(handleDialogHidden).toHaveBeenCalled();
+ expect(handleDialogConfirmed).toHaveBeenCalled();
+ expect(handleSubmit).toHaveBeenCalledTimes(1);
+ expect(handleWorkflowAction).not.toHaveBeenCalled();
+ expect(dialog.getAttribute('aria-hidden')).toEqual('true');
+
+ // The schedule publishing dialog should still be hidden
+ expect(otherDialog.getAttribute('aria-hidden')).toEqual('true');
+ });
});
describe('storing unsaved changes state to a checkbox input and update reload buttons accordingly', () => {
diff --git a/client/src/controllers/SessionController.ts b/client/src/controllers/SessionController.ts
index 918cc9249c..cbccee9157 100644
--- a/client/src/controllers/SessionController.ts
+++ b/client/src/controllers/SessionController.ts
@@ -87,14 +87,6 @@ export class SessionController extends Controller {
}
connect(): void {
- this.interceptTargets.forEach((button) => {
- // Match the event listener configuration of workflow-action that uses
- // capture so we can intercept the workflow-action's listener.
- button.addEventListener('click', this.showConfirmationDialog, {
- capture: true,
- });
- });
-
// Do a ping so the sessions list can be loaded immediately.
this.ping();
}
@@ -175,6 +167,12 @@ export class SessionController extends Controller {
// workflow action modal) after the user confirms the dialog.
if (!this.interceptValue || !this.hasWDialogOutlet) return;
+ // If the action button is inside a dialog, we need to hide the dialog first
+ // so it doesn't interfere with the confirmation dialog
+ this.lastActionButton
+ ?.closest('[data-controller="w-dialog"]')
+ ?.dispatchEvent(new Event('w-dialog:hide'));
+
// Prevent form submission
event.preventDefault();
// Prevent triggering other event listeners e.g. workflow actions modal
@@ -197,12 +195,32 @@ export class SessionController extends Controller {
}
wDialogOutletConnected(): void {
+ // Attach the event listener to the buttons that will be intercepted.
+ // Do it here instead of in connect() so hopefully this includes any buttons
+ // that are inside a dialog that is connected after this controller
+ // (e.g. the schedule publishing dialog).
+ this.interceptTargets.forEach((button) => {
+ // Match the event listener configuration of workflow-action that uses
+ // capture so we can intercept the workflow-action's listener.
+ button.addEventListener('click', this.showConfirmationDialog, {
+ capture: true,
+ });
+ });
+
this.wDialogOutlet.element.addEventListener(
'w-dialog:confirmed',
this.confirmAction,
);
}
+ wDialogOutletDisconnected(): void {
+ this.interceptTargets?.forEach((button) => {
+ button.removeEventListener('click', this.showConfirmationDialog, {
+ capture: true,
+ });
+ });
+ }
+
/**
* Sets the unsaved changes input state based on the event type dispatched by
* the w-unsaved controller. If the event type is w-unsaved:add, the input is
@@ -293,10 +311,5 @@ export class SessionController extends Controller {
if (this.interval) {
window.clearInterval(this.interval);
}
- this.interceptTargets?.forEach((button) => {
- button.removeEventListener('click', this.showConfirmationDialog, {
- capture: true,
- });
- });
}
}