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..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,6 +3,9 @@ import HTMLElement from '../html-element/HTMLElement';
import IDocumentFragment from '../document-fragment/IDocumentFragment';
import INode from '../node/INode';
import IHTMLTemplateElement from './IHTMLTemplateElement';
+import XMLParser from '../../xml-parser/XMLParser';
+import XMLSerializer from '../../xml-serializer/XMLSerializer';
+import DOMException from '../../exception/DOMException';
/**
* HTML Template Element.
@@ -11,105 +14,118 @@ import IHTMLTemplateElement from './IHTMLTemplateElement';
* 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();
/**
- * Returns the content.
- *
- * @returns Content.
+ * @override
+ */
+ public get innerHTML(): string {
+ return this.getInnerHTML();
+ }
+
+ /**
+ * @override
*/
- public get content(): IDocumentFragment {
- if (!this._contentElement) {
- this._contentElement = this.ownerDocument.createDocumentFragment();
+ public set innerHTML(html: string) {
+ 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);
}
- return this._contentElement;
}
/**
- * Previous sibling.
- *
- * @returns Node.
+ * @override
+ */
+ public get outerHTML(): string {
+ return new XMLSerializer().serializeToString(this.content);
+ }
+
+ /**
+ * @override
+ */
+ public set outerHTML(_html: string) {
+ throw new DOMException(
+ `Failed to set the 'outerHTML' property on 'Element': This element has no parent 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;
}
}
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..22d3879c3
--- /dev/null
+++ b/packages/happy-dom/test/nodes/html-template-element/HTMLTemplateElement.test.ts
@@ -0,0 +1,29 @@
+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!
';
+ 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);
+ });
+});