Automatic update from web-platform-tests HTML: headingoffset computation should not use the flat tree See https://github.com/whatwg/html/pull/12562 for context. -- wpt-commits: 691d45da216ab3677fa2b51daa903ec0b381ae3f wpt-pr: 60525
327 lines
13 KiB
HTML
327 lines
13 KiB
HTML
<!doctype html>
|
|
<meta charset="utf-8" />
|
|
<meta name="author" title="Keith Cirkel" href="mailto:wpt@keithcirkel.co.uk" />
|
|
<link rel="help" href="https://github.com/whatwg/html/pull/11086" />
|
|
<script src="/resources/testharness.js"></script>
|
|
<script src="/resources/testharnessreport.js"></script>
|
|
|
|
<div headingoffset="1" title="container headingoffset=1">
|
|
<!-- h1s are now h2s and so on -->
|
|
<h1 data-expected-offset="2"><!-- Level 2, h1 + 1 = 2 --></h1>
|
|
<h2 data-expected-offset="3"><!-- Level 3, h2 + 1 = 3 --></h2>
|
|
<h3 data-expected-offset="4"><!-- Level 4, h3 + 1 = 4 --></h3>
|
|
<div headingoffset="2" title="container headingoffset=2">
|
|
<!-- h1s are now h4s -->
|
|
<h1 data-expected-offset="4"><!-- Level 4, h1 + 2 + 1 = 4 --></h1>
|
|
<h2 data-expected-offset="5"><!-- Level 5, h2 + 2 + 1 = 5 --></h2>
|
|
<div headingreset title="container headingreset">
|
|
<!-- h1s are now h1s -->
|
|
<h1 data-expected-offset="1"><!-- Level 1, h1 (headingreset)--></h1>
|
|
</div>
|
|
<dialog open title="container dialog">
|
|
<!-- non-modal dialogs do not headingreset, h1s are still h4s -->
|
|
<h1 data-expected-offset="4"><!-- Level 4, h1 + 2 + 1 = 4 --></h1>
|
|
<h1 data-expected-offset="1" headingreset>
|
|
<!-- Level 1, h1 (headingreset) -->
|
|
</h1>
|
|
</dialog>
|
|
</div>
|
|
</div>
|
|
<!-- Clamping -->
|
|
<div headingoffset="8" title="container headingoffset=8">
|
|
<!-- h1s are now h9s -->
|
|
<h1 data-expected-offset="9"><!-- Level 9, h1 + 8 --></h1>
|
|
<h2 data-expected-offset="9"><!-- Level 9, h2 + 8 (clamped) --></h2>
|
|
<h3 data-expected-offset="9"><!-- Level 9, h3 + 8 (clamped) --></h3>
|
|
<h4 data-expected-offset="9"><!-- Level 9, h4 + 8 (clamped) --></h4>
|
|
<h5 data-expected-offset="9"><!-- Level 9, h5 + 8 (clamped) --></h5>
|
|
<h6 data-expected-offset="9"><!-- Level 9, h6 + 8 (clamped) --></h6>
|
|
<div headingreset title="container headingreset">
|
|
<!-- h1s are now h1s -->
|
|
<h1 data-expected-offset="1"><!-- Level 1, h1 (headingreset)--></h1>
|
|
</div>
|
|
<dialog open title="container dialog">
|
|
<!-- non-modal dialogs do not headingreset, h1s are still h4s -->
|
|
<h1 data-expected-offset="9"><!-- Level 9, h1 + 8 --></h1>
|
|
</dialog>
|
|
</div>
|
|
<!-- Negative headingoffsets are clamped to `0` -->
|
|
<div headingoffset="-3" title="container headingoffset=-3">
|
|
<h1 data-expected-offset="1"><!-- Level 1, h1 + (-3 clamped to 0) --></h1>
|
|
<h2 data-expected-offset="2"><!-- Level 2, h2 + (-3 clamped to 0) --></h2>
|
|
<h3 data-expected-offset="3"><!-- Level 3, h3 + (-3 clamped to 0) --></h3>
|
|
<h4 data-expected-offset="4"><!-- Level 4, h4 + (-3 clamped to 0) --></h4>
|
|
<h5 data-expected-offset="5"><!-- Level 5, h5 + (-3 clamped to 0) --></h5>
|
|
<h6 data-expected-offset="6"><!-- Level 6, h6 + (-3 clamped to 0) --></h6>
|
|
<div headingreset title="container headingreset">
|
|
<!-- h1s are now h1s -->
|
|
<h1 data-expected-offset="1"><!-- Level 1, h1 (headingreset)--></h1>
|
|
</div>
|
|
<dialog open title="container dialog">
|
|
<!-- non-modal dialogs do not headingreset, h1s are still h1s -->
|
|
<h1 data-expected-offset="1"><!-- Level 1, h1 + (-3 clamped to 0) --></h1>
|
|
</dialog>
|
|
</div>
|
|
<!-- Resetting applies after headingOffset -->
|
|
<div headingreset title="container headingreset + headingoffset">
|
|
<div headingoffset="2" headingreset>
|
|
<div headingoffset="2">
|
|
<h1 data-expected-offset="5"><!-- Level 5, h1 + 2 + 2 = 5 --></h1>
|
|
<h2 data-expected-offset="6"><!-- Level 6, h2 + 2 + 2 = 6 --></h2>
|
|
<h3 data-expected-offset="7"><!-- Level 7, h3 + 2 + 2 = 7 --></h3>
|
|
<h4 data-expected-offset="8"><!-- Level 8, h4 + 2 + 2 = 8 --></h4>
|
|
<h5 data-expected-offset="9"><!-- Level 9, h5 + 2 + 2 = 9 --></h5>
|
|
<h6 data-expected-offset="9">
|
|
<!-- Level 9, h6 + 2 + 2 = (10 clamped to 9) -->
|
|
</h6>
|
|
<h1 data-expected-offset="3" headingoffset="2" headingreset>
|
|
<!-- Level 3, h1 + 2 + (headingreset) -->
|
|
</h1>
|
|
<h2 data-expected-offset="4" headingoffset="2" headingreset>
|
|
<!-- Level 4, h2 + 2 + (headingreset) -->
|
|
</h2>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<!-- Ensure shadow roots work -->
|
|
<div headingoffset="1" title="container shadowroot headingoffset=1">
|
|
<template shadowrootmode="open">
|
|
<h1 data-expected-offset="2"><!-- Level 2, h1 + 1 --></h1>
|
|
<h2 data-expected-offset="2" headingreset>
|
|
<!-- Level 2, h2 (headingreset) -->
|
|
</h2>
|
|
</template>
|
|
</div>
|
|
<!-- Ensure slotted elements are correctly set -->
|
|
<div headingoffset="1" title="container shadowroot slotted headingoffset=1">
|
|
<template shadowrootmode="open">
|
|
<h1 data-expected-offset="2"><!-- Level 2, h1 + 1 --></h1>
|
|
<h2 data-expected-offset="3"><!-- Level 3, h2 + 1 --></h2>
|
|
<h3 data-expected-offset="3" headingreset>
|
|
<!-- Level 3, h3 (headingreset) -->
|
|
</h3>
|
|
<slot></slot>
|
|
</template>
|
|
<h1><!-- Level 2, h1 + 1 --></h1>
|
|
</div>
|
|
<!-- Ensure slotted elements respect their parents -->
|
|
<div
|
|
headingoffset="1"
|
|
title="container shadowroot slotted with container headingoffset=1"
|
|
>
|
|
<template shadowrootmode="open">
|
|
<h1 data-expected-offset="2"><!-- Level 2, h1 + 1 --></h1>
|
|
<div headingoffset="1" title="container inside shadowroot headingoffset=1">
|
|
<slot></slot>
|
|
</div>
|
|
</template>
|
|
<h2 data-expected-offset="3"><!-- Level 3, h2 + 1 --></h2>
|
|
<h4 data-expected-offset="5"><!-- Level 5, h4 + 1 --></h4>
|
|
<h4 data-expected-offset="4" headingreset>
|
|
<!-- Level 4, h4 (headingreset) -->
|
|
</h4>
|
|
</div>
|
|
<!-- Ensure the slot's headingoffset does not affect slotted content -->
|
|
<div
|
|
headingoffset="1"
|
|
title="container shadowroot slot with attr headingoffset=1"
|
|
>
|
|
<template shadowrootmode="open">
|
|
<h1 data-expected-offset="2"><!-- Level 2, h1 + 1 --></h1>
|
|
<slot headingoffset="1"></slot>
|
|
</template>
|
|
<h2 data-expected-offset="3"><!-- Level 3, h2 + 1 --></h2>
|
|
</div>
|
|
<h1 data-expected-offset="2" headingoffset="1"><!-- Level 2, h1 + 1 --></h1>
|
|
<h2 data-expected-offset="3" headingoffset="1"><!-- Level 3, h2 + 1 --></h2>
|
|
<h1 data-expected-offset="3" headingoffset="2"><!-- Level 3, h1 + 2--></h1>
|
|
<h2 data-expected-offset="4" headingoffset="2"><!-- Level 4, h2 + 2 --></h2>
|
|
<h1 data-expected-offset="2" headingoffset="1" headingreset>
|
|
<!-- Level 2, h1 + 1 (headingreset) -->
|
|
</h1>
|
|
<h2 data-expected-offset="3" headingoffset="1" headingreset>
|
|
<!-- Level 3, h2 + 1 (headingreset) -->
|
|
</h2>
|
|
<h1 data-expected-offset="3" headingoffset="2" headingreset>
|
|
<!-- Level 3, h1 + 2 (headingreset) -->
|
|
</h1>
|
|
<h2 data-expected-offset="4" headingoffset="2" headingreset>
|
|
<!-- Level 4, h2 + 2 (headingreset) -->
|
|
</h2>
|
|
<h1 data-expected-offset="9" headingoffset="20" headingreset>
|
|
<!-- Level 9, h1 + 20 (clamped) -->
|
|
</h1>
|
|
<h2 data-expected-offset="9" headingoffset="20" headingreset>
|
|
<!-- Level 9, h2 + 20 (clamped) -->
|
|
</h2>
|
|
<h1 data-expected-offset="1" headingoffset="0" headingreset>
|
|
<!-- Level 1, h1 + 0 -->
|
|
</h1>
|
|
<h2 data-expected-offset="2" headingoffset="0" headingreset>
|
|
<!-- Level 2, h2 + 0 -->
|
|
</h2>
|
|
<div title="container with no attr">
|
|
<h1 data-expected-offset="2" headingoffset="1"><!-- Level 2, h1 + 1 --></h1>
|
|
<h2 data-expected-offset="3" headingoffset="1"><!-- Level 3, h2 + 1 --></h2>
|
|
<h1 data-expected-offset="2" headingoffset="1" headingreset>
|
|
<!-- Level 2, h1 + 1 -->
|
|
</h1>
|
|
<h2 data-expected-offset="3" headingoffset="1" headingreset>
|
|
<!-- Level 3, h2 + 1 -->
|
|
</h2>
|
|
<h1 data-expected-offset="1" headingoffset="-1" headingreset>
|
|
<!-- Level 1, h1 + (-1 clamped to 0) -->
|
|
</h1>
|
|
<h2 data-expected-offset="2" headingoffset="-1" headingreset>
|
|
<!-- Level 2, h2 + (-1 clamped to 0) -->
|
|
</h2>
|
|
</div>
|
|
<div headingreset title="many nested + and - values">
|
|
<div headingoffset="-1">
|
|
<div headingoffset="3">
|
|
<div headingoffset="-6">
|
|
<div headingoffset="1">
|
|
<h1 data-expected-offset="5">
|
|
<!-- Level 5, h1 + 1 + (-6 clamped to 0) + 3 + (-1 clamped to 0) -->
|
|
</h1>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<h1 data-expected-offset="9" headingoffset="9" aria-level="3">
|
|
<!-- Level 3 -->
|
|
</h1>
|
|
|
|
<div headingoffset="9" id="modalParent">
|
|
<dialog id="modal">
|
|
<h1></h1>
|
|
</dialog>
|
|
</div>
|
|
|
|
<script>
|
|
const attribute = (el, val) => el.setAttribute("headingoffset", val);
|
|
const property = (el, val) => (el.headingOffset = val);
|
|
const levels = [1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
const matchAllLevels = (el) =>
|
|
levels.map((l) => el.matches(`:heading(${l})`));
|
|
|
|
for (const fn of [attribute, property]) {
|
|
test(function () {
|
|
const el = document.createElement("h1");
|
|
assert_true(el.matches(":heading"), `h1 should match :heading`);
|
|
assert_true(el.matches(":heading(1)"), `h1 should match :heading(1)`);
|
|
assert_equals(
|
|
el.headingOffset,
|
|
0,
|
|
`h1 has an initial headingOffset of 0`,
|
|
);
|
|
fn(el, 3);
|
|
assert_equals(el.headingOffset, 3, `h1 now has a headingOffset of 3`);
|
|
assert_false(
|
|
el.matches(":heading(1)"),
|
|
`h1[headingoffset=3] should no longer match :heading(1)`,
|
|
);
|
|
assert_true(
|
|
el.matches(":heading(4)"),
|
|
`h1[headingoffset=3] should match :heading(4)`,
|
|
);
|
|
}, `headingoffset (set via ${fn.name}) should change the level a heading matches against`);
|
|
|
|
test(function () {
|
|
const parent = document.createElement("div");
|
|
const el = document.createElement("h1");
|
|
parent.append(el);
|
|
assert_true(el.matches(":heading"), `h1 should match :heading`);
|
|
assert_true(el.matches(":heading(1)"), `h1 should match :heading(1)`);
|
|
assert_equals(
|
|
parent.headingOffset,
|
|
0,
|
|
`parent has an initial headingOffset of 0`,
|
|
);
|
|
fn(parent, 3);
|
|
assert_equals(parent.headingOffset, 3, `h1 now has a headingOffset of 3`);
|
|
assert_false(
|
|
el.matches(":heading(1)"),
|
|
`h1[headingoffset=3] should no longer match :heading(1)`,
|
|
);
|
|
assert_true(
|
|
el.matches(":heading(4)"),
|
|
`div[headingoffset=3] h1 should match :heading(4)`,
|
|
);
|
|
const bools = matchAllLevels(el);
|
|
const expected_bools = levels.map((l) => l == 4);
|
|
assert_array_equals(
|
|
bools,
|
|
expected_bools,
|
|
`${el.outerHTML} should match only the expected heading level`,
|
|
);
|
|
assert_false(el.headingReset, "h1 has an initial headingReset=false");
|
|
el.headingReset = true;
|
|
assert_true(el.headingReset, "h1 now has a headingReset of true");
|
|
assert_false(
|
|
el.matches(":heading(4)"),
|
|
`div[headingoffset=3] h1[headingreset] should not match :heading(4)`,
|
|
);
|
|
assert_true(
|
|
el.matches(":heading(1)"),
|
|
`div[headingoffset=3] h1[headingreset] should match :heading(1)`,
|
|
);
|
|
const reset_bools = matchAllLevels(el);
|
|
const reset_expected_bools = levels.map((l) => l == 1);
|
|
assert_array_equals(
|
|
reset_bools,
|
|
reset_expected_bools,
|
|
`${el.outerHTML} should match only the expected heading level`,
|
|
);
|
|
}, `headingoffset (set via ${fn.name}) should change the level when a parent changes offset`);
|
|
}
|
|
|
|
test(function (t) {
|
|
const el = modal.querySelector("h1");
|
|
assert_false(modal.headingReset, `modal dialog has not set heading reset`);
|
|
modal.showModal();
|
|
t.add_cleanup(() => modal.close());
|
|
|
|
assert_false(modal.headingReset, `modal dialogs return headingReset false by default`);
|
|
assert_true(el.matches(":heading"), `h1 inside modal should match :heading`);
|
|
assert_true(el.matches(":heading(9)"), `h1 inside modal should match :heading(9)`);
|
|
modal.headingReset = true;
|
|
assert_true(el.matches(":heading(1)"), `h1 inside modal should match :heading(1) if modal is headingreset`);
|
|
const bools = matchAllLevels(el);
|
|
const expected_bools = levels.map((l) => l == 1);
|
|
assert_array_equals(
|
|
bools,
|
|
expected_bools,
|
|
`${el.outerHTML} should match only the expected heading level`,
|
|
);
|
|
}, `headingoffset should not impact modals or explicit headingreset containers`);
|
|
|
|
let i = 0;
|
|
for (const el of document.querySelectorAll("[data-expected-offset]")) {
|
|
i += 1;
|
|
test(function () {
|
|
const expected = parseInt(el.getAttribute("data-expected-offset"));
|
|
assert_true(
|
|
expected > 0 && expected < 10,
|
|
"expected offset should be a level from 1 to 9",
|
|
);
|
|
assert_true(
|
|
el.matches(":heading"),
|
|
`${el.outerHTML} should match :heading`,
|
|
);
|
|
const bools = matchAllLevels(el);
|
|
const expected_bools = levels.map((l) => l == expected);
|
|
assert_true(
|
|
el.matches(`:heading(${expected})`),
|
|
`${el.outerHTML} should match :heading(${expected})`,
|
|
);
|
|
assert_array_equals(
|
|
bools,
|
|
expected_bools,
|
|
`${el.outerHTML} should match only the expected heading level`,
|
|
);
|
|
}, `case ${i}: heading level for ${el.outerHTML} should match based on expected document structure`);
|
|
}
|
|
</script>
|