Skip to content

Commit

Permalink
Merge pull request #506 from Mas0nShi/451-fixes-missing-innerHTML-in-…
Browse files Browse the repository at this point in the history
…html-template

#451 fixes missing inner html in html template
  • Loading branch information
capricorn86 committed Jun 28, 2022
2 parents f4320c3 + 0833019 commit 7667c0a
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 42 deletions.
Expand Up @@ -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.
Expand All @@ -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 <IHTMLTemplateElement>super.cloneNode(deep);
const clone = <IHTMLTemplateElement>super.cloneNode(deep);
(<IDocumentFragment>clone.content) = this.content.cloneNode(deep);
return clone;
}
}
@@ -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 = <HTMLTemplateElement>document.createElement('template');
});

afterEach(() => {
jest.restoreAllMocks();
});

it('InnerHTML', () => {
const div = '<div>happy-dom is cool!</div>';
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);
});
});

0 comments on commit 7667c0a

Please sign in to comment.