Skip to content

Commit

Permalink
#456@patch: Fixes problem with Document.activeElement still pointing …
Browse files Browse the repository at this point in the history
…to an Element that has been disconnected from the DOM.
  • Loading branch information
capricorn86 committed Oct 12, 2022
1 parent 3ee3996 commit 597f22e
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 1 deletion.
4 changes: 4 additions & 0 deletions packages/happy-dom/src/nodes/document/Document.ts
Expand Up @@ -345,6 +345,10 @@ export default class Document extends Node implements IDocument {
* @returns Active element.
*/
public get activeElement(): IHTMLElement {
if (this._activeElement && !this._activeElement.isConnected) {
this._activeElement = null;
}

if (this._activeElement) {
let rootNode: IShadowRoot | IDocument = <IShadowRoot | IDocument>(
this._activeElement.getRootNode()
Expand Down
3 changes: 3 additions & 0 deletions packages/happy-dom/src/nodes/node/Node.ts
Expand Up @@ -552,6 +552,9 @@ export default class Node extends EventTarget implements INode {
if (isConnected && this.connectedCallback) {
this.connectedCallback();
} else if (!isConnected && this.disconnectedCallback) {
if (this.ownerDocument['_activeElement'] === this) {
this.ownerDocument['_activeElement'] = null;
}
this.disconnectedCallback();
}

Expand Down
2 changes: 1 addition & 1 deletion packages/happy-dom/src/nodes/shadow-root/ShadowRoot.ts
Expand Up @@ -54,7 +54,7 @@ export default class ShadowRoot extends DocumentFragment implements IShadowRoot
*/
public get activeElement(): IHTMLElement {
const activeElement: IHTMLElement = this.ownerDocument['_activeElement'];
if (activeElement && activeElement.getRootNode() === this) {
if (activeElement && activeElement.isConnected && activeElement.getRootNode() === this) {
return activeElement;
}
return null;
Expand Down
16 changes: 16 additions & 0 deletions packages/happy-dom/test/nodes/document/Document.test.ts
Expand Up @@ -320,6 +320,22 @@ describe('Document', () => {
expect(document.activeElement === document.body).toBe(true);
});

it('Unsets the active element when it gets disconnected.', () => {
const div = <IHTMLElement>document.createElement('div');

document.appendChild(div);

expect(document.activeElement === document.body).toBe(true);

div.focus();

expect(document.activeElement === div).toBe(true);

div.remove();

expect(document.activeElement === document.body).toBe(true);
});

it('Returns the first custom element that has document as root node when the focused element is nestled in multiple shadow roots.', () => {
class CustomElementA extends (<Window>window).HTMLElement {
constructor() {
Expand Down
20 changes: 20 additions & 0 deletions packages/happy-dom/test/nodes/shadow-root/ShadowRoot.test.ts
Expand Up @@ -68,6 +68,26 @@ describe('ShadowRoot', () => {

expect(shadowRoot.activeElement === null).toBe(true);
});

it('Unsets the active element when it gets disconnected.', () => {
const customElement = document.createElement('custom-element');
const shadowRoot = customElement.shadowRoot;
const div = <IHTMLElement>document.createElement('div');

document.body.appendChild(customElement);

shadowRoot.appendChild(div);

expect(shadowRoot.activeElement === null).toBe(true);

div.focus();

expect(shadowRoot.activeElement === div).toBe(true);

customElement.remove();

expect(shadowRoot.activeElement === null).toBe(true);
});
});

describe('toString()', () => {
Expand Down

0 comments on commit 597f22e

Please sign in to comment.