Ensure submit buttons inside dialogs also trigger the overwrite confirmation dialog

pull/12182/head
Sage Abdullah 2024-07-24 17:27:09 +01:00 zatwierdzone przez Thibaud Colas
rodzic 7eabf7eeb9
commit 4f7db41030
2 zmienionych plików z 115 dodań i 16 usunięć

Wyświetl plik

@ -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 */ `
<div role="document">
<div id="schedule-publishing-dialog-body" data-w-dialog-target="body">
Set the publishing schedule
<input type="datetime-local" name="go_live_at" />
<input type="datetime-local" name="expire_at" />
<button type="submit">Save schedule</button>
</div>
</div>
`;
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', () => {

Wyświetl plik

@ -87,14 +87,6 @@ export class SessionController extends Controller<HTMLElement> {
}
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<HTMLElement> {
// 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<HTMLElement> {
}
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<HTMLElement> {
if (this.interval) {
window.clearInterval(this.interval);
}
this.interceptTargets?.forEach((button) => {
button.removeEventListener('click', this.showConfirmationDialog, {
capture: true,
});
});
}
}