mirror of
https://github.com/wagtail/wagtail.git
synced 2024-11-29 01:22:07 +01:00
fix: MutationObserver in dirty form check only tests direct descendants
Fixes #11142
This commit is contained in:
parent
caf9142c5d
commit
00474a6152
@ -22,6 +22,7 @@ Changelog
|
|||||||
* Fix: Resolve issue local development of docs when running `make livehtml` (Sage Abdullah)
|
* Fix: Resolve issue local development of docs when running `make livehtml` (Sage Abdullah)
|
||||||
* Fix: Resolve issue with unwanted padding in chooser modal listings (Sage Abdullah)
|
* Fix: Resolve issue with unwanted padding in chooser modal listings (Sage Abdullah)
|
||||||
* Fix: Ensure form builder emails that have date or datetime fields correctly localize dates based on the configured `LANGUAGE_CODE` (Mark Niehues)
|
* Fix: Ensure form builder emails that have date or datetime fields correctly localize dates based on the configured `LANGUAGE_CODE` (Mark Niehues)
|
||||||
|
* Fix: Ensure the Stimulus `UnsavedController` checks for nested removal/additions of inputs so that the unsaved warning shows in more valid cases when editing a page (Karthik Ayangar)
|
||||||
* Docs: Add contributing development documentation on how to work with a fork of Wagtail (Nix Asteri, Dan Braghis)
|
* Docs: Add contributing development documentation on how to work with a fork of Wagtail (Nix Asteri, Dan Braghis)
|
||||||
* Docs: Make sure the settings panel is listed in tabbed interface examples (Tibor Leupold)
|
* Docs: Make sure the settings panel is listed in tabbed interface examples (Tibor Leupold)
|
||||||
* Docs: Update content and page names to their US spelling instead of UK spelling (Victoria Poromon)
|
* Docs: Update content and page names to their US spelling instead of UK spelling (Victoria Poromon)
|
||||||
|
@ -112,6 +112,96 @@ describe('UnsavedController', () => {
|
|||||||
expect(events['w-unsaved:add']).toHaveLength(1);
|
expect(events['w-unsaved:add']).toHaveLength(1);
|
||||||
expect(events['w-unsaved:add'][0]).toHaveProperty('detail.type', 'edits');
|
expect(events['w-unsaved:add'][0]).toHaveProperty('detail.type', 'edits');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should allow checking for when an input is removed', async () => {
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0);
|
||||||
|
|
||||||
|
await setup();
|
||||||
|
|
||||||
|
// setup should not fire any event
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0);
|
||||||
|
|
||||||
|
const input = document.getElementById('name');
|
||||||
|
|
||||||
|
input.remove();
|
||||||
|
|
||||||
|
await jest.runAllTimersAsync();
|
||||||
|
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(1);
|
||||||
|
expect(events['w-unsaved:add'][0]).toHaveProperty('detail.type', 'edits');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ignore when non-inputs are added', async () => {
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0); // Ensure no initial events
|
||||||
|
|
||||||
|
await setup();
|
||||||
|
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0); // Verify no events after setup
|
||||||
|
|
||||||
|
// Act (simulate the addition of a paragraph)
|
||||||
|
const paragraph = document.createElement('p');
|
||||||
|
paragraph.id = 'paraName';
|
||||||
|
paragraph.textContent = 'This is a new paragraph'; // Add some content for clarity
|
||||||
|
document.getElementsByTagName('form')[0].appendChild(paragraph); // paragraph is added
|
||||||
|
|
||||||
|
await jest.runAllTimersAsync();
|
||||||
|
|
||||||
|
// Assert (verify no events were fired)
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire an event when a textarea is added', async () => {
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0); // Ensure no initial events
|
||||||
|
|
||||||
|
await setup();
|
||||||
|
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0); // Verify no events after setup
|
||||||
|
|
||||||
|
// Act (simulate adding a textarea with value)
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
textarea.value = 'Some initial content';
|
||||||
|
textarea.id = 'taName';
|
||||||
|
document.getElementsByTagName('form')[0].appendChild(textarea);
|
||||||
|
|
||||||
|
await jest.runAllTimersAsync(); // Allow any timers to trigger
|
||||||
|
|
||||||
|
// Assert (verify event was fired)
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(1);
|
||||||
|
expect(events['w-unsaved:add'][0]).toHaveProperty('detail.type', 'edits');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire an event when a nested input (select) is added', async () => {
|
||||||
|
// Arrange
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0); // Ensure no initial events
|
||||||
|
|
||||||
|
await setup();
|
||||||
|
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(0); // Verify no events after setup
|
||||||
|
|
||||||
|
// Act
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const select = document.createElement('select');
|
||||||
|
select.id = 'mySelect';
|
||||||
|
|
||||||
|
const option1 = document.createElement('option');
|
||||||
|
option1.value = 'option1';
|
||||||
|
option1.textContent = 'Option 1';
|
||||||
|
select.appendChild(option1);
|
||||||
|
|
||||||
|
const option2 = document.createElement('option');
|
||||||
|
option2.value = 'option2';
|
||||||
|
option2.textContent = 'Option 2';
|
||||||
|
select.appendChild(option2);
|
||||||
|
|
||||||
|
div.appendChild(select);
|
||||||
|
document.body.getElementsByTagName('form')[0].appendChild(div);
|
||||||
|
|
||||||
|
await jest.runAllTimersAsync();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
expect(events['w-unsaved:add']).toHaveLength(1);
|
||||||
|
expect(events['w-unsaved:add'][0]).toHaveProperty('detail.type', 'edits');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('showing a confirmation message when exiting the browser tab', () => {
|
describe('showing a confirmation message when exiting the browser tab', () => {
|
||||||
|
@ -198,6 +198,17 @@ export class UnsavedController extends Controller<HTMLFormElement> {
|
|||||||
if (current !== previous) this.notify();
|
if (current !== previous) this.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getIsValidNode(node: Node | null) {
|
||||||
|
if (!node || node.nodeType !== node.ELEMENT_NODE) return false;
|
||||||
|
|
||||||
|
const validElements = ['input', 'textarea', 'select'];
|
||||||
|
|
||||||
|
return (
|
||||||
|
validElements.includes((node as Element).localName) ||
|
||||||
|
(node as Element).querySelector(validElements.join(',')) !== null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify the user of changes to the form.
|
* Notify the user of changes to the form.
|
||||||
* Dispatch events to update the footer message via dispatching events.
|
* Dispatch events to update the footer message via dispatching events.
|
||||||
@ -288,15 +299,11 @@ export class UnsavedController extends Controller<HTMLFormElement> {
|
|||||||
detail: { initialFormData },
|
detail: { initialFormData },
|
||||||
});
|
});
|
||||||
|
|
||||||
const isValidInputNode = (node) =>
|
|
||||||
node.nodeType === node.ELEMENT_NODE &&
|
|
||||||
['INPUT', 'TEXTAREA', 'SELECT'].includes(node.tagName);
|
|
||||||
|
|
||||||
const observer = new MutationObserver((mutationList) => {
|
const observer = new MutationObserver((mutationList) => {
|
||||||
const hasMutationWithValidInputNode = mutationList.some(
|
const hasMutationWithValidInputNode = mutationList.some(
|
||||||
(mutation) =>
|
(mutation) =>
|
||||||
Array.from(mutation.addedNodes).some(isValidInputNode) ||
|
Array.from(mutation.addedNodes).some(this.getIsValidNode) ||
|
||||||
Array.from(mutation.removedNodes).some(isValidInputNode),
|
Array.from(mutation.removedNodes).some(this.getIsValidNode),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hasMutationWithValidInputNode) this.check();
|
if (hasMutationWithValidInputNode) this.check();
|
||||||
|
@ -35,6 +35,7 @@ depth: 1
|
|||||||
* Resolve issue local development of docs when running `make livehtml` (Sage Abdullah)
|
* Resolve issue local development of docs when running `make livehtml` (Sage Abdullah)
|
||||||
* Resolve issue with unwanted padding in chooser modal listings (Sage Abdullah)
|
* Resolve issue with unwanted padding in chooser modal listings (Sage Abdullah)
|
||||||
* Ensure form builder emails that have date or datetime fields correctly localize dates based on the configured `LANGUAGE_CODE` (Mark Niehues)
|
* Ensure form builder emails that have date or datetime fields correctly localize dates based on the configured `LANGUAGE_CODE` (Mark Niehues)
|
||||||
|
* Ensure the Stimulus `UnsavedController` checks for nested removal/additions of inputs so that the unsaved warning shows in more valid cases when editing a page (Karthik Ayangar)
|
||||||
|
|
||||||
|
|
||||||
### Documentation
|
### Documentation
|
||||||
|
Loading…
Reference in New Issue
Block a user