diff --git a/source b/source index 2d7effe1d68..011a20c825f 100644 --- a/source +++ b/source @@ -3328,6 +3328,7 @@ a.setAttribute('href', 'https://example.com/'); // change the content attribute
CharacterData node and its
replace data algorithmProcessingInstruction nodeforshadowrootmodeshadowrootdelegatesfocusshadowrootclonableIn a rendering, the template element represents nothing.
The for content
+ attribute identifies the ProcessingInstruction that marks the location to insert
+ content at (<?marker>) or the start of the range to replace
+ (<?start>).
The shadowrootmode content attribute is an
enumerated attribute with the following keywords and states:
Each template element has an associated
+ Element-or-ShadowRoot-or-null insertion target, which is
+ initially null.
Each template element has an associated ProcessingInstruction-or-null
+ insertion start marker and insertion end marker, which are initially
+ null.
The adopting steps
(with node and oldDocument as parameters) for template elements
@@ -68106,6 +68122,124 @@ interface HTMLTemplateElement : HTMLElement {
To prepare content patching given a node scope and a
+ template element template:
Assert: template's for
+ attribute is specified.
Let markerName be template's for attribute's value.
If markerName is the empty string, then return false.
Let (start, end) be the result of find markers + given scope and markerName.
If start is null, then return false.
Set template's insertion target to + start's parent.
Set template's insertion start marker to + start.
Set template's insertion end marker to end.
If start is end, then return true.
Let currentNode be start's next sibling.
While currentNode is not null:
+ +If currentNode is end, then break.
Let nextNode be currentNode's + next sibling.
Remove currentNode.
Let currentNode be nextNode.
Return true.
To find markers given a node scope and a string name:
+ +For each descendant of scope's descendants, in tree order:
+ +If descendant is not a ProcessingInstruction node, then
+ continue.
If descendant's name attribute's value is not
+ name, then continue.
If descendant's target is "marker", then return (descendant, descendant).
If descendant's target is "start":
Let start be descendant.
Let nesting level be 0.
Let sibling be start's next sibling.
While sibling is not null:
+ +If sibling is not a ProcessingInstruction node, then
+ continue.
If sibling's target is an "start", then increment nesting level by one.
Otherwise, if sibling's target is
+ "end":
If nesting level is 0, then return (start, + sibling).
Otherwise, decrement nesting level by one.
Let sibling be sibling's next sibling.
Return (start, null).
+ +No matching <?end> was found, which is interpreted
+ as a range from start to the end of its parent.
Return (null, null).
In this example, a template element with a for attribute is used to stream a document out-of-order,
+ sending fast static content first and recommendations computed async as they become available on
+ the server.
<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>Async recommendation engine</title>
+ <style>
+ aside {
+ /* position the aside where it can grow without causing layout shift or obscuring other content */
+ }
+ aside:has(.placeholder) {
+ /* style the placeholder content */
+ }
+ </style>
+ </head>
+ <body>
+ <h1>How to train your cat</h1>
+ <p>Set realistic goals and don't expect your cat to make a perfect cup of tea
+ on the first try.</p>
+ <aside>
+ <p>Recommended reading:</p>
+ <?start name="recommended">
+ <ul class="placeholder">
+ <li>...</li>
+ <li>...</li>
+ <li>...</li>
+ </ul>
+ <?end>
+ </aside>
+ <p>...</p>
+ <p>Now sit back and enjoy your tea with your cat.</p>
+
+ <!-- The server has a potentially long delay at this point. -->
+
+ <template for="recommended">
+ <ul>
+ <li>Cat or butler, which is right for you?</li>
+ <li>Rewarding good cat behavior</li>
+ <li>Kettles considered harmful</li>
+ </ul>
+ </template>
+ </body>
+</html>
+
+ The content between <?start name="recommended> and <?end> is replaced with the template contents. Since the new
+ content does not use class="placeholder", the placeholder styling no
+ longer applies.
If the adjusted insertion location is inside a template
- element, let it instead be inside the template element's template
- contents, after its last child (if any).
If adjusted insertion location is inside a template element:
Let template be that element.
Let target be template's insertion target.
If target is not null:
+ +If template's insertion end marker is not null and its + parent is target, then set adjusted insertion location to + inside target, before template's insertion end + marker.
+ +If the end marker has been removed or moved to another node, nodes are + instead appended to target in the following step.
+Otherwise, set adjusted insertion location to inside target, + after its last child (if any).
Otherwise, set adjusted insertion location to inside template's + template contents, after its last child (if any).
shadowrootmode is not in the None state;for attribute is
+ not specified; orthen insert an HTML element for the token.
+then insert an HTML element for the token and return.
Otherwise:
+If templateStartTag's shadowrootmode is not in the None state:
Let declarativeShadowHostElement be adjusted current @@ -140289,6 +140510,67 @@ document.body.appendChild(text);
Otherwise, if templateStartTag's for
+ attribute is specified:
Let scope be the current node.
+ +In the fragment case, scope can be the root
+ html element of the temporary document. This makes it possible to modify
+ already-parsed content in the fragment.
If scope is a template element, then set scope to
+ scope's template contents.
This is to support patching inside plain template elements or
+ those using shadowrootmode. Nested
+ patching is not supported, since in this case scope's template
+ contents will be empty and prepare content patching will fail.
Otherwise, if scope is the body element of its node + document, then set scope to its parent.
+ +This is to support patching head with a template
+ inside body.
Let template be the result of insert a foreign element for + templateStartTag, with HTML namespace and true.
Let success be the result of prepare content patching given + scope and template.
If success is false:
+ +Assert: template is the current node.
Pop the current node off the stack of open + elements.
Insert an element at the adjusted insertion location with + template.
Push template onto the stack of open elements.
+ +The above steps undo the effect of the onlyAddToElementStack + argument from the insert a foreign element call that created + template, inserting it where it would have been inserted otherwise. This is to + signal an error.
+If the current node is not a template element, then this is a
parse error.
Otherwise, if current node's insertion target is not null:
+ +Let start be current node's insertion start + marker.
+ +Let end be current node's insertion end + marker.
+ +Assert: start is not null.
If start's parent is not null, then remove start.
If end is not null and end's parent is not null, + then remove end.
Set current node's insertion target to null.
Set current node's insertion start marker to null.
Set current node's insertion end marker to null.
Pop elements from the stack of open elements until a template
element has been popped from the stack.
output
for
+ template
+ form
button;