From 63a480093ea8bbac4ea20863781e9beda5b3d2bf Mon Sep 17 00:00:00 2001 From: Mas0nShi Date: Wed, 15 Jun 2022 10:52:58 +0800 Subject: [PATCH 1/3] #451@patch: Fixes missing innerHTML in html-template. --- .../HTMLTemplateElement.ts | 24 ++++++++++++++++++ .../HTMLTemplateElement.test.ts | 25 +++++++++++++++++++ 2 files changed, 49 insertions(+) create mode 100644 packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts diff --git a/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts b/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts index 075b20743..5eef807d8 100644 --- a/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts +++ b/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts @@ -3,6 +3,7 @@ import HTMLElement from '../html-element/HTMLElement'; import IDocumentFragment from '../document-fragment/IDocumentFragment'; import INode from '../node/INode'; import IHTMLTemplateElement from './IHTMLTemplateElement'; +import XMLSerializer from '../../xml-serializer/XMLSerializer'; /** * HTML Template Element. @@ -13,6 +14,29 @@ import IHTMLTemplateElement from './IHTMLTemplateElement'; export default class HTMLTemplateElement extends HTMLElement implements IHTMLTemplateElement { private _contentElement: IDocumentFragment = null; + /** + * Sets inner HTML. + * + * @param html HTML. + */ + public set innerHTML(html: string) { + super.innerHTML = html; + } + + /** + * Returns inner HTML. + * + * @returns HTML. + */ + public get innerHTML(): string { + const xmlSerializer = new XMLSerializer(); + let xml = ''; + for (const node of this.content.childNodes) { + xml += xmlSerializer.serializeToString(node); + } + return xml; + } + /** * Returns the content. * diff --git a/packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts b/packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts new file mode 100644 index 000000000..0447b9d2d --- /dev/null +++ b/packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts @@ -0,0 +1,25 @@ +import Window from '../../../src/window/Window'; +import Document from '../../../src/nodes/document/Document'; +import HTMLTemplateElement from '../../../src/nodes/html-template-element/HTMLTemplateElement'; + +describe('HTMLTemplateElement', () => { + let window: Window; + let document: Document; + let element: HTMLTemplateElement; + + beforeEach(() => { + window = new Window(); + document = window.document; + element = document.createElement('template'); + }); + + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('InnerHTML', () => { + const div = '
happy-dom is cool!
'; + element.innerHTML = div; + expect(element.innerHTML).toBe(div); + }); +}); From 157dbcffe56325dc57b8c625ee9eae912ab70d6d Mon Sep 17 00:00:00 2001 From: Mas0nShi Date: Wed, 15 Jun 2022 11:02:07 +0800 Subject: [PATCH 2/3] #451@patch: Continue fixes missing innerHTML in html-template. --- .../nodes/html-template-element/HTMLTemplateElement.ts | 9 ++++++++- .../html-template-element/HTMLTemplateElement.test.ts | 4 ++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts b/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts index 5eef807d8..f9208b6b1 100644 --- a/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts +++ b/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts @@ -4,6 +4,7 @@ import IDocumentFragment from '../document-fragment/IDocumentFragment'; import INode from '../node/INode'; import IHTMLTemplateElement from './IHTMLTemplateElement'; import XMLSerializer from '../../xml-serializer/XMLSerializer'; +import XMLParser from '../../xml-parser/XMLParser'; /** * HTML Template Element. @@ -20,7 +21,13 @@ export default class HTMLTemplateElement extends HTMLElement implements IHTMLTem * @param html HTML. */ public set innerHTML(html: string) { - super.innerHTML = html; + for (const child of this.content.childNodes.slice()) { + this.content.removeChild(child); + } + + for (const node of XMLParser.parse(this.ownerDocument, html).childNodes.slice()) { + this.content.appendChild(node); + } } /** diff --git a/packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts b/packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts index 0447b9d2d..22d3879c3 100644 --- a/packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts +++ b/packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts @@ -19,7 +19,11 @@ describe('HTMLTemplateElement', () => { it('InnerHTML', () => { const div = '
happy-dom is cool!
'; + expect(element.content.childNodes.length).toBe(0); element.innerHTML = div; expect(element.innerHTML).toBe(div); + expect(element.content.childNodes.length).toBe(1); + element.innerHTML = ''; + expect(element.content.childNodes.length).toBe(0); }); }); From af05c45253c646778f7d9901cf1d248b08cbce11 Mon Sep 17 00:00:00 2001 From: Mas0nShi Date: Thu, 16 Jun 2022 00:13:25 +0800 Subject: [PATCH 3/3] #451@patch: Continue fixes missing innerHTML in html-template. --- .../HTMLTemplateElement.ts | 99 ++++++++----------- 1 file changed, 42 insertions(+), 57 deletions(-) diff --git a/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts b/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts index f9208b6b1..8911a01da 100644 --- a/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts +++ b/packages/happy-dom/src/nodes/html-template-element/HTMLTemplateElement.ts @@ -3,8 +3,9 @@ import HTMLElement from '../html-element/HTMLElement'; import IDocumentFragment from '../document-fragment/IDocumentFragment'; import INode from '../node/INode'; import IHTMLTemplateElement from './IHTMLTemplateElement'; -import XMLSerializer from '../../xml-serializer/XMLSerializer'; import XMLParser from '../../xml-parser/XMLParser'; +import XMLSerializer from '../../xml-serializer/XMLSerializer'; +import DOMException from '../../exception/DOMException'; /** * HTML Template Element. @@ -13,12 +14,17 @@ import XMLParser from '../../xml-parser/XMLParser'; * https://developer.mozilla.org/en-US/docs/Web/API/HTMLTemplateElement. */ export default class HTMLTemplateElement extends HTMLElement implements IHTMLTemplateElement { - private _contentElement: IDocumentFragment = null; + public readonly content: IDocumentFragment = this.ownerDocument.createDocumentFragment(); /** - * Sets inner HTML. - * - * @param html HTML. + * @override + */ + public get innerHTML(): string { + return this.getInnerHTML(); + } + + /** + * @override */ public set innerHTML(html: string) { for (const child of this.content.childNodes.slice()) { @@ -31,116 +37,95 @@ export default class HTMLTemplateElement extends HTMLElement implements IHTMLTem } /** - * Returns inner HTML. - * - * @returns HTML. + * @override */ - public get innerHTML(): string { - const xmlSerializer = new XMLSerializer(); - let xml = ''; - for (const node of this.content.childNodes) { - xml += xmlSerializer.serializeToString(node); - } - return xml; + public get outerHTML(): string { + return new XMLSerializer().serializeToString(this.content); } /** - * Returns the content. - * - * @returns Content. + * @override */ - public get content(): IDocumentFragment { - if (!this._contentElement) { - this._contentElement = this.ownerDocument.createDocumentFragment(); - } - return this._contentElement; + public set outerHTML(_html: string) { + throw new DOMException( + `Failed to set the 'outerHTML' property on 'Element': This element has no parent node.` + ); } /** - * Previous sibling. - * - * @returns Node. + * @override */ public get previousSibling(): INode { return this.content.previousSibling; } /** - * Next sibling. - * - * @returns Node. + * @override */ public get nextSibling(): INode { return this.content.nextSibling; } /** - * First child. - * - * @returns Node. + * @override */ public get firstChild(): INode { return this.content.firstChild; } /** - * Last child. - * - * @returns Node. + * @override */ public get lastChild(): INode { return this.content.lastChild; } /** - * Append a child node to childNodes. - * - * @param node Node to append. - * @returns Appended node. + * @override + */ + public getInnerHTML(options?: { includeShadowRoots?: boolean }): string { + const xmlSerializer = new XMLSerializer(); + let xml = ''; + for (const node of this.content.childNodes) { + xml += xmlSerializer.serializeToString(node, options); + } + return xml; + } + + /** + * @override */ public appendChild(node: INode): INode { return this.content.appendChild(node); } /** - * Remove Child element from childNodes array. - * - * @param node Node to remove. + * @override */ public removeChild(node: Node): INode { return this.content.removeChild(node); } /** - * Inserts a node before another. - * - * @param newNode Node to insert. - * @param referenceNode Node to insert before. - * @returns Inserted node. + * @override */ public insertBefore(newNode: INode, referenceNode: INode): INode { return this.content.insertBefore(newNode, referenceNode); } /** - * Replaces a node with another. - * - * @param newChild New child. - * @param oldChild Old child. - * @returns Replaced node. + * @override */ public replaceChild(newChild: INode, oldChild: INode): INode { return this.content.replaceChild(newChild, oldChild); } /** - * Clones a node. - * * @override - * @param [deep=false] "true" to clone deep. - * @returns Cloned node. */ public cloneNode(deep = false): IHTMLTemplateElement { - return super.cloneNode(deep); + const clone = super.cloneNode(deep); + (clone.content) = this.content.cloneNode(deep); + return clone; } }