From df3b78b877b88150a090c1c2a9b8dec854086b5e Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Tue, 15 Jul 2025 11:55:14 -0700 Subject: [PATCH 01/10] Prevent infinite loop in revealing algorithms The ancestor details revealing algorithm and the hidden until found revealing algorithm may both get stuck in infinite loops because they iterate the flat tree while firing synchronous events. If the page were to listen to these events and change the flat tree in response, then the algorithm could theoretically never end. Fixes https://github.com/whatwg/html/issues/11436 --- source | 70 +++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 47 insertions(+), 23 deletions(-) diff --git a/source b/source index 142c43dfb1f..ae55c404b0a 100644 --- a/source +++ b/source @@ -61535,30 +61535,43 @@ interface HTMLDetailsElement : HTMLElement {

The ancestor details revealing algorithm is to run the following steps on - currentNode:

+ target:

    +
  1. Let ancestors be « ».

  2. + +
  3. Let currentNode be target.

  4. +
  5. While currentNode has a parent node within the flat tree:

    +
      +
    1. Append currentNode to + ancestors.

    2. + +
    3. Set currentNode to the parent node of currentNode within the + flat tree.

    4. +
    +
  6. + +
  7. +

    For each ancestor of ancestors:

    +
    1. -

      If currentNode is slotted into the second slot of a details +

      If ancestor is slotted into the second slot of a details element:

        -
      1. Set currentNode to the details element which - currentNode is slotted into.

      2. +
      3. Let details be the details element which + ancestor is slotted into.

      4. If the open attribute is not set on - currentNode, then set - the open attribute on currentNode to the + details, then set + the open attribute on details to the empty string.

    2. - -
    3. Otherwise, set currentNode to the parent node of - currentNode within the flat tree.

@@ -79874,31 +79887,42 @@ END:VCARD

The ancestor hidden-until-found revealing algorithm is to run the following steps on - currentNode:

+ target:

    +
  1. Let ancestors be « ».

  2. + +
  3. Let currentNode be target.

  4. +
  5. While currentNode has a parent node within the flat tree:

      -
    1. -

      If currentNode has the hidden attribute in the - Hidden Until Found state, then:

      - -
        -
      1. Fire an event named beforematch at currentNode with the bubbles attribute initialized to true.

      2. - -
      3. Remove the hidden attribute from - currentNode.

      4. -
      -
    2. +
    3. Append currentNode to + ancestors.

    4. Set currentNode to the parent node of currentNode within the flat tree.

  6. + +
  7. +

    For each ancestor of ancestors:

    + +
      +

      If ancestor has the hidden attribute in the + Hidden Until Found state, then:

      + +
        +
      1. Fire an event named beforematch at ancestor with the bubbles attribute initialized to true.

      2. + +
      3. Remove the hidden attribute from + ancestor.

      4. +
      +
    +
From 1b704f0670375e3e6a141c1c5e1e41fed98cbba4 Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Tue, 15 Jul 2025 13:30:53 -0700 Subject: [PATCH 02/10] fix nesting --- source | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/source b/source index ae55c404b0a..2800bc8708f 100644 --- a/source +++ b/source @@ -79910,17 +79910,19 @@ END:VCARD

For each ancestor of ancestors:

    -

    If ancestor has the hidden attribute in the - Hidden Until Found state, then:

    +
  1. +

    If ancestor has the hidden attribute in the + Hidden Until Found state, then:

    -
      -
    1. Fire an event named beforematch at ancestor with the bubbles attribute initialized to true.

    2. +
        +
      1. Fire an event named beforematch at ancestor with the bubbles attribute initialized to true.

      2. -
      3. Remove the hidden attribute from - ancestor.

      4. -
      +
    3. Remove the hidden attribute from + ancestor.

    4. +
    +
From 6ef43777dbc1ac79df96a56ee8c3b644b79aae87 Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Wed, 16 Jul 2025 13:45:50 -0700 Subject: [PATCH 03/10] combine algorithms and reduce traversals --- source | 111 ++++++++++++++++++--------------------------------------- 1 file changed, 35 insertions(+), 76 deletions(-) diff --git a/source b/source index 5bbb64da4b4..d10115d25d6 100644 --- a/source +++ b/source @@ -61532,48 +61532,6 @@ interface HTMLDetailsElement : HTMLElement { -

The ancestor details revealing algorithm is to run the following steps on - target:

- -
    -
  1. Let ancestors be « ».

  2. - -
  3. Let currentNode be target.

  4. - -
  5. -

    While currentNode has a parent node within the flat tree:

    - -
      -
    1. Append currentNode to - ancestors.

    2. - -
    3. Set currentNode to the parent node of currentNode within the - flat tree.

    4. -
    -
  6. - -
  7. -

    For each ancestor of ancestors:

    - -
      -
    1. -

      If ancestor is slotted into the second slot of a details - element:

      - -
        -
      1. Let details be the details element which - ancestor is slotted into.

      2. - -
      3. If the open attribute is not set on - details, then set - the open attribute on details to the - empty string.

      4. -
      -
    2. -
    -
  8. -
-

The following example shows the details element being used to hide technical @@ -79730,8 +79688,7 @@ END:VCARD data-x="navigate-fragid">fragment navigation. When these features attempt to scroll to a target which is in the element's subtree, the user agent will remove the hidden attribute in order to reveal the content before scrolling to - it by running the ancestor hidden-until-found revealing algorithm on the target - node.

+ it by running the ancestor revealing algorithm on the target node.

@@ -79886,43 +79843,55 @@ END:VCARD string.

-

The ancestor hidden-until-found revealing algorithm is to run the following steps on +

The ancestor revealing algorithm is to run the following steps on target:

    -
  1. Let ancestors be « ».

  2. +
  3. Let hiddenUntilFoundAncestors be « ».

  4. -
  5. Let currentNode be target.

  6. +
  7. Let detailsAncestors be « ».

  8. + +
  9. Let ancestor be target.

  10. -

    While currentNode has a parent node within the flat tree:

    +

    While ancestor has a parent node within the flat tree:

      -
    1. Append currentNode to - ancestors.

    2. +
    3. If ancestor has the hidden attribute in the + Hidden Until Found state, then append ancestor to + hiddenUntilFoundAncestors.

    4. -
    5. Set currentNode to the parent node of currentNode within the +

    6. If ancestor is slotted into the second slot of a details + element, then append the details element which + ancestor is slotted into to detailsAncestors.

    7. + +
    8. Set ancestor to the parent node of ancestor within the flat tree.

  11. -

    For each ancestor of ancestors:

    +

    For each hiddenUntilFound of hiddenUntilFoundAncestors:

      -
    1. -

      If ancestor has the hidden attribute in the - Hidden Until Found state, then:

      +
    2. Fire an event named beforematch at ancestor with the bubbles attribute initialized to true.

    3. -
        -
      1. Fire an event named beforematch at ancestor with the bubbles attribute initialized to true.

      2. +
      3. Remove the hidden attribute from + ancestor.

      4. +
      + -
    4. Remove the hidden attribute from - ancestor.

    5. -
    -
  12. +
  13. +

    For each details of detailsAncestors:

    + +
      +
    1. If the open attribute is not set on + details, then set + the open attribute on details to the + empty string.

@@ -83796,15 +83765,8 @@ body { display:none } match.

  • Queue a global task on the user interaction task source given - node's relevant global object to run the following steps:

    - -
      -
    1. Run the ancestor details revealing algorithm on node.

    2. - -
    3. Run the ancestor hidden-until-found revealing algorithm on - node.

    4. -
    -
  • + node's relevant global object to run the ancestor revealing + algorithm on node.

    @@ -106044,10 +106006,7 @@ location.href = '#foo';

  • Set document's target element to target.

  • -
  • Run the ancestor details revealing algorithm on target.

  • - -
  • Run the ancestor hidden-until-found revealing algorithm on - target.

  • +
  • Run the ancestor revealing algorithm on target.

  • Scroll target into view, with behavior set to "auto", block set to "start", and inline From f7f0dfd636afc5682a37bdaffc4510135057d2e6 Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Tue, 22 Jul 2025 15:12:14 -0700 Subject: [PATCH 04/10] combine list and check preconditions --- source | 56 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/source b/source index d10115d25d6..8d039cd362a 100644 --- a/source +++ b/source @@ -79847,9 +79847,7 @@ END:VCARD target:

      -
    1. Let hiddenUntilFoundAncestors be « ».

    2. - -
    3. Let detailsAncestors be « ».

    4. +
    5. Let ancestorsToReveal be « ».

    6. Let ancestor be target.

    7. @@ -79860,11 +79858,12 @@ END:VCARD
    8. If ancestor has the hidden attribute in the Hidden Until Found state, then append ancestor to - hiddenUntilFoundAncestors.

    9. + ancestorsToReveal.

    10. If ancestor is slotted into the second slot of a details - element, then append the details element which - ancestor is slotted into to detailsAncestors.

    11. + element which has the open attribute, then append the details element which ancestor + is slotted into to ancestorsToReveal.

    12. Set ancestor to the parent node of ancestor within the flat tree.

    13. @@ -79872,26 +79871,41 @@ END:VCARD
    14. -

      For each hiddenUntilFound of hiddenUntilFoundAncestors:

      +

      For each ancestorToReveal of ancestorsToReveal:

        -
      1. Fire an event named beforematch at ancestor with the bubbles attribute initialized to true.

      2. +
      3. If ancestorToReveal is not connected, then return.

      4. -
      5. Remove the hidden attribute from - ancestor.

      6. -
      -
    15. +
    16. +

      If ancestorToReveal is a details element:

      -
    17. -

      For each details of detailsAncestors:

      +
        +

        If ancestorToReveal does not have the open attribute, then return.

        -
          -
        1. If the open attribute is not set on - details, then set - the open attribute on details to the - empty string.

        2. +

          Remove the open attribute from + ancestorToReveal.

          +
        + + +
      1. +

        Otherwise:

        + +
          +
        1. Fire an event named beforematch at ancestor with the bubbles attribute initialized to true.

        2. + +
        3. If ancestorToReveal is not connected, then return.

        4. + +
        5. If ancestorToReveal's hidden attribute is + not in the Hidden Until Found state, then + return.

        6. + +
        7. Remove the hidden attribute from + ancestorToReveal.

        8. +
        +
    From a1e907953d72119aee40ff930fe63b6f56fef6ff Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Tue, 22 Jul 2025 15:16:37 -0700 Subject: [PATCH 05/10] add missing li --- source | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source b/source index 8d039cd362a..df7c5f52818 100644 --- a/source +++ b/source @@ -79880,11 +79880,11 @@ END:VCARD

    If ancestorToReveal is a details element:

      -

      If ancestorToReveal does not have the open attribute, then return.

      +
    1. If ancestorToReveal does not have the open attribute, then return.

    2. -

      Remove the open attribute from - ancestorToReveal.

      +
    3. Remove the open attribute from + ancestorToReveal.

  • From 7b0c806e53346a6d6b30abc138d94b73a5d3b69c Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Wed, 23 Jul 2025 08:10:26 -0700 Subject: [PATCH 06/10] nits --- source | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/source b/source index df7c5f52818..6936d66dc25 100644 --- a/source +++ b/source @@ -79843,8 +79843,7 @@ END:VCARD string.

    -

    The ancestor revealing algorithm is to run the following steps on - target:

    +

    The ancestor revealing algorithm given a node target is:

    1. Let ancestorsToReveal be « ».

    2. @@ -79855,15 +79854,15 @@ END:VCARD

      While ancestor has a parent node within the flat tree:

        -
      1. If ancestor has the hidden attribute in the +

      2. If ancestor has a hidden attribute in the Hidden Until Found state, then append ancestor to ancestorsToReveal.

      3. If ancestor is slotted into the second slot of a details - element which has the open attribute, then append the details element which ancestor - is slotted into to ancestorsToReveal.

      4. + element which does not have an open attribute, then + append the details element which + ancestor is slotted into to ancestorsToReveal.

      5. Set ancestor to the parent node of ancestor within the flat tree.

      6. @@ -79876,20 +79875,20 @@ END:VCARD
        1. If ancestorToReveal is not connected, then return.

        2. -
        3. -

          If ancestorToReveal is a details element:

          +
        4. If ancestorToReveal is a details element, then set the open attribute on ancestorToReveal to the empty + string.

        5. -
            -
          1. If ancestorToReveal does not have the open attribute, then return.

          2. +
          3. If ancestorToReveal is not connected, then return.

          4. -
          5. Remove the open attribute from - ancestorToReveal.

          6. -
          - +
        6. If ancestorToReveal is not a details element and does not have + the hidden attribute in the Hidden Until Found state, then return.

        7. -

          Otherwise:

          +

          If ancestorToReveal has a hidden + attribute in the Hidden Until Found state, + then:

          1. Fire an event named Date: Mon, 28 Jul 2025 08:11:03 -0700 Subject: [PATCH 07/10] nits --- source | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/source b/source index 6936d66dc25..046fcbef12f 100644 --- a/source +++ b/source @@ -79886,13 +79886,12 @@ END:VCARD data-x="attr-hidden-until-found-state">Hidden Until Found state, then return.

          2. -

            If ancestorToReveal has a hidden - attribute in the Hidden Until Found state, - then:

            +

            If ancestorToReveal has a hidden attribute in + the Hidden Until Found state:

            1. Fire an event named beforematch at ancestor with the beforematch at ancestorToReveal with the bubbles attribute initialized to true.

            2. If ancestorToReveal is not connected, then return.

            3. From 61af6a08a1750a0569f448b90e8bf56f774b531c Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Mon, 28 Jul 2025 08:26:24 -0700 Subject: [PATCH 08/10] use a tuple --- source | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/source b/source index 30827b0d98b..684a5faf351 100644 --- a/source +++ b/source @@ -80524,6 +80524,10 @@ END:VCARD string.

            +

            An ancestor reveal pair is a tuple consisting of a node and a string.

            +

            The ancestor revealing algorithm given a node target is:

              @@ -80537,13 +80541,13 @@ END:VCARD
              1. If ancestor has a hidden attribute in the Hidden Until Found state, then append ancestor to - ancestorsToReveal.

              2. + data-x="list append">append (ancestor, "untilfound") + to ancestorsToReveal.

              3. If ancestor is slotted into the second slot of a details element which does not have an open attribute, then - append the details element which - ancestor is slotted into to ancestorsToReveal.

              4. + append (the details, "details") to ancestorsToReveal.

              5. Set ancestor to the parent node of ancestor within the flat tree.

              6. @@ -80551,26 +80555,23 @@ END:VCARD
              7. -

                For each ancestorToReveal of ancestorsToReveal:

                +

                For each ancestorToRevealPair of ancestorsToReveal:

                  -
                1. If ancestorToReveal is not connected, then return.

                2. - -
                3. If ancestorToReveal is a details element, then set the open attribute on ancestorToReveal to the empty - string.

                4. +
                5. Let ancestorToReveal be ancestorToRevalPair's node.

                6. If ancestorToReveal is not connected, then return.

                7. -
                8. If ancestorToReveal is not a details element and does not have - the hidden attribute in the Hidden Until Found state, then return.

                9. -
                10. -

                  If ancestorToReveal has a hidden attribute in - the Hidden Until Found state:

                  +

                  If ancestorToRevealPair's string is "untilfound":

                    +
                  1. If ancestorToReveal's hidden attribute is + not in the Hidden Until Found state, then + return.

                  2. +
                  3. Fire an event named beforematch at ancestorToReveal with the bubbles attribute initialized to true.

                  4. @@ -80584,6 +80585,22 @@ END:VCARD
                  5. Remove the hidden attribute from ancestorToReveal.

                  +
                11. + +
                12. +

                  Otherwise:

                  + +
                    +
                  1. Assert: ancestorToRevealPair's string is "details".

                  2. + +
                  3. If ancestorToReveal has the open + attribute, then return.

                  4. + +
                  5. Set ancestorToReveal's open + attribute to the empty string.

                  6. +
              8. From 80cc5590ee860d5f0dfc6551d75678abf640b25e Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Tue, 29 Jul 2025 10:18:41 -0700 Subject: [PATCH 09/10] nits --- source | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/source b/source index 684a5faf351..46cf0942b02 100644 --- a/source +++ b/source @@ -80541,12 +80541,12 @@ END:VCARD
                1. If ancestor has a hidden attribute in the Hidden Until Found state, then append (ancestor, "untilfound") + data-x="list append">append (ancestor, "until-found") to ancestorsToReveal.

                2. If ancestor is slotted into the second slot of a details element which does not have an open attribute, then - append (the details, "append (ancestor's parent node, "details") to ancestorsToReveal.

                3. Set ancestor to the parent node of ancestor within the @@ -80558,14 +80558,13 @@ END:VCARD

                  For each ancestorToRevealPair of ancestorsToReveal:

                    -
                  1. Let ancestorToReveal be ancestorToRevalPair's node.

                  2. +
                  3. Let (ancestorToReveal, revealType) be + ancestorToRevealPair.

                  4. If ancestorToReveal is not connected, then return.

                  5. -

                    If ancestorToRevealPair's string is "untilfound":

                    +

                    If revealType is "until-found":

                    1. If ancestorToReveal's hidden attribute is @@ -80591,11 +80590,10 @@ END:VCARD

                      Otherwise:

                        -
                      1. Assert: ancestorToRevealPair's string is "

                        Assert: revealType is "details".

                      2. -
                      3. If ancestorToReveal has the open +

                      4. If ancestorToReveal has an open attribute, then return.

                      5. Set ancestorToReveal's open From 85646c4e1a4d86e1b392b0a3615e47a8a69ff518 Mon Sep 17 00:00:00 2001 From: Joey Arhar Date: Wed, 30 Jul 2025 05:01:19 -0700 Subject: [PATCH 10/10] improve tuple destructor --- source | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/source b/source index 46cf0942b02..73cb032dedd 100644 --- a/source +++ b/source @@ -80555,12 +80555,10 @@ END:VCARD

                      6. -

                        For each ancestorToRevealPair of ancestorsToReveal:

                        +

                        For each (ancestorToReveal, revealType) of + ancestorsToReveal:

                          -
                        1. Let (ancestorToReveal, revealType) be - ancestorToRevealPair.

                        2. -
                        3. If ancestorToReveal is not connected, then return.