fix(type): focus switch between contenteditables in shadow dom (#13510)
Firefox has a bug: calling `node.focus()` does make the node focused, but some internal "current contenteditable node" is not changed. Blurring the previous one and focusing the new one helps.
This commit is contained in:
parent
ae4d2e75aa
commit
7a5b070e95
|
|
@ -663,7 +663,14 @@ export class InjectedScript {
|
|||
return 'error:notconnected';
|
||||
if (node.nodeType !== Node.ELEMENT_NODE)
|
||||
throw this.createStacklessError('Node is not an element');
|
||||
const wasFocused = (node.getRootNode() as (Document | ShadowRoot)).activeElement === node && node.ownerDocument && node.ownerDocument.hasFocus();
|
||||
|
||||
const activeElement = (node.getRootNode() as (Document | ShadowRoot)).activeElement;
|
||||
const wasFocused = activeElement === node && node.ownerDocument && node.ownerDocument.hasFocus();
|
||||
if (!wasFocused && activeElement && (activeElement as HTMLElement | SVGElement).blur) {
|
||||
// Workaround the Firefox bug where focusing the element does not switch current
|
||||
// contenteditable to the new element. However, blurring the previous one helps.
|
||||
(activeElement as HTMLElement | SVGElement).blur();
|
||||
}
|
||||
(node as HTMLElement | SVGElement).focus();
|
||||
|
||||
if (resetSelectionIfNotFocused && !wasFocused && node.nodeName.toLowerCase() === 'input') {
|
||||
|
|
|
|||
|
|
@ -476,6 +476,48 @@ it('should support simple copy-pasting', async ({ page, isMac, browserName }) =>
|
|||
expect(await page.evaluate(() => document.querySelector('div').textContent)).toBe('123123');
|
||||
});
|
||||
|
||||
it('should type repeatedly in contenteditable in shadow dom', async ({ page }) => {
|
||||
it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/12941' });
|
||||
|
||||
await page.setContent(`
|
||||
<html>
|
||||
<body>
|
||||
<shadow-element></shadow-element>
|
||||
<script>
|
||||
customElements.define('shadow-element', class extends HTMLElement {
|
||||
constructor() {
|
||||
super();
|
||||
this.attachShadow({ mode: 'open' });
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
this.shadowRoot.innerHTML = \`
|
||||
<style>
|
||||
.editor { padding: 1rem; margin: 1rem; border: 1px solid #ccc; }
|
||||
</style>
|
||||
<div class=editor contenteditable id=foo></div>
|
||||
<hr>
|
||||
<section>
|
||||
<div class=editor contenteditable id=bar></div>
|
||||
</section>
|
||||
\`;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
|
||||
const editor = page.locator('shadow-element > .editor').first();
|
||||
await editor.type('This is the first box.');
|
||||
|
||||
const sectionEditor = page.locator('section .editor');
|
||||
await sectionEditor.type('This is the second box.');
|
||||
|
||||
expect(await editor.textContent()).toBe('This is the first box.');
|
||||
expect(await sectionEditor.textContent()).toBe('This is the second box.');
|
||||
});
|
||||
|
||||
async function captureLastKeydown(page) {
|
||||
const lastEvent = await page.evaluateHandle(() => {
|
||||
const lastEvent = {
|
||||
|
|
|
|||
Loading…
Reference in a new issue