kopia lustrzana https://github.com/wagtail/wagtail
Ensure submit buttons inside dialogs also trigger the overwrite confirmation dialog
rodzic
7eabf7eeb9
commit
4f7db41030
|
@ -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', () => {
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue