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
  • The attribute list concept
  • The data of a CharacterData node and its replace data algorithm
  • +
  • The target of a ProcessingInstruction node
  • The child text content of a node
  • The descendant text content of a node
  • The name, @@ -67863,6 +67864,7 @@ not-slash = %x0000-002E / %x0030-10FFFF
    Nothing (for clarification, see example).
    Content attributes:
    Global attributes
    +
    for
    shadowrootmode
    shadowrootdelegatesfocus
    shadowrootclonable
    @@ -67879,6 +67881,7 @@ interface HTMLTemplateElement : HTMLElement { [HTMLConstructor] constructor(); readonly attribute DocumentFragment content; + [CEReactions, Reflect="for"] attribute DOMString htmlFor; [CEReactions] attribute DOMString shadowRootMode; [CEReactions, Reflect] attribute boolean shadowRootDelegatesFocus; [CEReactions, Reflect] attribute boolean shadowRootClonable; @@ -67894,6 +67897,11 @@ interface HTMLTemplateElement : HTMLElement {

    In 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:

    @@ -68049,6 +68057,14 @@ interface HTMLTemplateElement : HTMLElement { +

    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:

    + +
      +
    1. Assert: template's for + attribute is specified.

    2. + +
    3. Let markerName be template's for attribute's value.

    4. + +
    5. If markerName is the empty string, then return false.

    6. + +
    7. Let (start, end) be the result of find markers + given scope and markerName.

    8. + +
    9. If start is null, then return false.

    10. + +
    11. Set template's insertion target to + start's parent.

    12. + +
    13. Set template's insertion start marker to + start.

    14. + +
    15. Set template's insertion end marker to end.

    16. + +
    17. If start is end, then return true.

    18. + +
    19. Let currentNode be start's next sibling.

    20. + +
    21. +

      While currentNode is not null:

      + +
        +
      1. If currentNode is end, then break.

      2. + +
      3. Let nextNode be currentNode's + next sibling.

      4. + +
      5. Remove currentNode.

      6. + +
      7. Let currentNode be nextNode.

      8. +
      + +
    22. Return true.

    23. +
    +
    + +
    +

    To find markers given a node scope and a string name:

    + +
      +
    1. +

      For each descendant of scope's descendants, in tree order:

      + +
        +
      1. If descendant is not a ProcessingInstruction node, then + continue.

      2. + +
      3. If descendant's name attribute's value is not + name, then continue.

      4. + +
      5. If descendant's target is "marker", then return (descendant, descendant).

      6. + +
      7. +

        If descendant's target is "start":

        + +
          +
        1. Let start be descendant.

        2. + +
        3. Let nesting level be 0.

        4. + +
        5. Let sibling be start's next sibling.

        6. + +
        7. +

          While sibling is not null:

          + +
            +
          1. If sibling is not a ProcessingInstruction node, then + continue.

          2. + +
          3. If sibling's target is an "start", then increment nesting level by one.

          4. + +
          5. +

            Otherwise, if sibling's target is + "end":

            + +
              +
            1. If nesting level is 0, then return (start, + sibling).

            2. + +
            3. Otherwise, decrement nesting level by one.

            4. +
            +
          6. + +
          7. Let sibling be sibling's next sibling.

          8. +
          +
        8. + +
        9. +

          Return (start, null).

          + +

          No matching <?end> was found, which is interpreted + as a range from start to the end of its parent.

          +
        10. +
        +
      8. +
      +
    2. + +
    3. Return (null, null).

    4. +
    +
    +
    @@ -68159,6 +68293,62 @@ interface HTMLTemplateElement : HTMLElement {
    +
    + +

    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.

    +
    + +
    @@ -139261,9 +139451,35 @@ dictionary StorageEventInit : EventInit {
  • -

    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:

    + +
      +
    1. Let template be that element.

    2. + +
    3. Let target be template's insertion target.

    4. + +
    5. +

      If target is not null:

      + +
        +
      1. +

        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.

        +
      2. + +
      3. Otherwise, set adjusted insertion location to inside target, + after its last child (if any).

      4. +
      +
    6. + +
    7. Otherwise, set adjusted insertion location to inside template's + template contents, after its last child (if any).

    8. +
  • @@ -140198,7 +140414,10 @@ document.body.appendChild(text); -

    then 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:

    1. Let declarativeShadowHostElement be adjusted current @@ -140289,6 +140510,67 @@ document.body.appendChild(text);

  • + +
  • +

    Otherwise, if templateStartTag's for + attribute is specified:

    + +
      +
    1. +

      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.

      +
    2. + +
    3. +

      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.

      +
    4. + +
    5. +

      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.

      +
    6. + +
    7. Let template be the result of insert a foreign element for + templateStartTag, with HTML namespace and true.

    8. + +
    9. Let success be the result of prepare content patching given + scope and template.

    10. + +
    11. +

      If success is false:

      + +
        +
      1. Assert: template is the current node.

      2. + +
      3. Pop the current node off the stack of open + elements.

      4. + +
      5. Insert an element at the adjusted insertion location with + template.

      6. + +
      7. +

        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.

        +
      +
    12. +
    +
  • @@ -140305,6 +140587,32 @@ document.body.appendChild(text);
  • 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:

    + +
      +
    1. Let start be current node's insertion start + marker.

      + +
    2. Let end be current node's insertion end + marker.

      + +
    3. Assert: start is not null.

    4. + +
    5. If start's parent is not null, then remove start.

    6. + +
    7. If end is not null and end's parent is not null, + then remove end.

    8. + +
    9. Set current node's insertion target to null.

    10. + +
    11. Set current node's insertion start marker to null.

    12. + +
    13. Set current node's insertion end marker to null.

    14. +
    +
  • +
  • Pop elements from the stack of open elements until a template element has been popped from the stack.

  • @@ -152859,6 +153167,11 @@ interface External { output Specifies controls from which the output was calculated Unordered set of unique space-separated tokens consisting of IDs* + + for + template + Updates existing content + Text form button;