Skip to content

Commit

Permalink
fix: [#1592] Fixes bug where Document.activeElement is set to the wro…
Browse files Browse the repository at this point in the history
…ng target when triggering HTMLSelectElement.focus (#1600)
  • Loading branch information
capricorn86 authored Nov 11, 2024
1 parent 562ecb4 commit e038cf9
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 16 deletions.
28 changes: 12 additions & 16 deletions packages/happy-dom/src/nodes/html-element/HTMLElementUtility.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,10 @@ export default class HTMLElementUtility {
* @param element Element.
*/
public static blur(element: HTMLElement | SVGElement): void {
const document = element[PropertySymbol.ownerDocument];
const target = element[PropertySymbol.proxy] || element;
const document = target[PropertySymbol.ownerDocument];

if (
document[PropertySymbol.activeElement] !== element ||
!element[PropertySymbol.isConnected]
) {
if (document[PropertySymbol.activeElement] !== target || !target[PropertySymbol.isConnected]) {
return;
}

Expand All @@ -28,15 +26,15 @@ export default class HTMLElementUtility {

document[PropertySymbol.clearCache]();

element.dispatchEvent(
target.dispatchEvent(
new FocusEvent('blur', {
relatedTarget,
bubbles: false,
composed: true,
cancelable: true
})
);
element.dispatchEvent(
target.dispatchEvent(
new FocusEvent('focusout', {
relatedTarget,
bubbles: true,
Expand All @@ -52,17 +50,15 @@ export default class HTMLElementUtility {
* @param element Element.
*/
public static focus(element: HTMLElement | SVGElement): void {
const document = element[PropertySymbol.ownerDocument];
const target = element[PropertySymbol.proxy] || element;
const document = target[PropertySymbol.ownerDocument];

if (
document[PropertySymbol.activeElement] === element ||
!element[PropertySymbol.isConnected]
) {
if (document[PropertySymbol.activeElement] === target || !target[PropertySymbol.isConnected]) {
return;
}

// Set the next active element so `blur` can use it for `relatedTarget`.
document[PropertySymbol.nextActiveElement] = element;
document[PropertySymbol.nextActiveElement] = target;

const relatedTarget = document[PropertySymbol.activeElement];

Expand All @@ -73,18 +69,18 @@ export default class HTMLElementUtility {
// Clean up after blur, so it does not affect next blur call.
document[PropertySymbol.nextActiveElement] = null;

document[PropertySymbol.activeElement] = element;
document[PropertySymbol.activeElement] = target;

document[PropertySymbol.clearCache]();

element.dispatchEvent(
target.dispatchEvent(
new FocusEvent('focus', {
relatedTarget,
bubbles: false,
composed: true
})
);
element.dispatchEvent(
target.dispatchEvent(
new FocusEvent('focusin', {
relatedTarget,
bubbles: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,16 @@ describe('HTMLSelectElement', () => {
});
});

describe('focus()', () => {
it('Should set Document.activeElement to the proxy.', () => {
document.body.appendChild(element);
element.focus();
expect(document.activeElement).toBe(element);
element.blur();
expect(document.activeElement).toBe(document.body);
});
});

for (const method of ['checkValidity', 'reportValidity']) {
describe(`${method}()`, () => {
it('Returns "true" if the field is "disabled".', () => {
Expand Down

0 comments on commit e038cf9

Please sign in to comment.