Skip to content

Commit c4380b9

Browse files
committed
handle template's original content
When the document fragment is called via the content method on a templat, it must contain the original template's HTML nodes.
1 parent 2f2870c commit c4380b9

File tree

3 files changed

+46
-1
lines changed

3 files changed

+46
-1
lines changed

src/browser/dom/node.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,23 @@ pub const Node = struct {
390390
return parser.nodeHasChildNodes(self);
391391
}
392392

393+
fn is_template(self: *parser.Node) !bool {
394+
if (parser.nodeType(self) != .element) {
395+
return false;
396+
}
397+
398+
const e = parser.nodeToElement(self);
399+
return try parser.elementTag(e) == .template;
400+
}
401+
393402
pub fn get_childNodes(self: *parser.Node, page: *Page) !NodeList {
403+
// special case for template:
404+
// > The Node.childNodes property of the <template> element is always empty
405+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/template#usage_notes
406+
if (try is_template(self)) {
407+
return .{};
408+
}
409+
394410
const allocator = page.arena;
395411
var list: NodeList = .{};
396412

src/browser/html/elements.zig

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ const DataSet = @import("DataSet.zig");
3333
const StyleSheet = @import("../cssom/StyleSheet.zig");
3434
const CSSStyleDeclaration = @import("../cssom/CSSStyleDeclaration.zig");
3535

36+
const WalkerChildren = @import("../dom/walker.zig").WalkerChildren;
37+
3638
// HTMLElement interfaces
3739
pub const Interfaces = .{
3840
Element,
@@ -1200,11 +1202,22 @@ pub const HTMLTemplateElement = struct {
12001202
pub const subtype = .node;
12011203

12021204
pub fn get_content(self: *parser.Template, page: *Page) !*parser.DocumentFragment {
1203-
const state = try page.getOrCreateNodeState(@ptrCast(@alignCast(self)));
1205+
const n: *parser.Node = @ptrCast(@alignCast(self));
1206+
const state = try page.getOrCreateNodeState(n);
12041207
if (state.template_content) |tc| {
12051208
return tc;
12061209
}
12071210
const tc = try parser.documentCreateDocumentFragment(@ptrCast(page.window.document));
1211+
const ntc: *parser.Node = @ptrCast(@alignCast(tc));
1212+
1213+
// move existing template's childnodes to the fragment.
1214+
const walker = WalkerChildren{};
1215+
var next: ?*parser.Node = null;
1216+
while (true) {
1217+
next = try walker.get_next(n, next) orelse break;
1218+
_ = try parser.nodeAppendChild(ntc, next.?);
1219+
}
1220+
12081221
state.template_content = tc;
12091222
return tc;
12101223
}

src/tests/html/template.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,19 @@
2020
testing.expectEqual('P', t.content.childNodes[1].tagName);
2121
testing.expectEqual('9000!', t.content.childNodes[1].innerHTML);
2222
</script>
23+
24+
<template id="hello"><p>hello, world</p></template>
25+
26+
<script id=template_parsing>
27+
const tt = document.getElementById('hello');
28+
testing.expectEqual('<p>hello, world</p>', tt.innerHTML);
29+
30+
// > The Node.childNodes property of the <template> element is always empty
31+
// https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/template#usage_notes
32+
testing.expectEqual(0, tt.childNodes.length);
33+
34+
let out = document.createElement('div');
35+
out.appendChild(tt.content.cloneNode(true));
36+
37+
testing.expectEqual('<p>hello, world</p>', out.innerHTML);
38+
</script>

0 commit comments

Comments
 (0)