Skip to content

Commit

Permalink
Auto-generate IDs for all <dt> elements (mdn#5190)
Browse files Browse the repository at this point in the history
  • Loading branch information
sideshowbarker authored Feb 6, 2022
1 parent 4db34bb commit f1aedef
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 61 deletions.
1 change: 1 addition & 0 deletions kumascript/macros/EmbedLiveSample.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
// See also : LiveSampleLink
var sampleId = $0 || $token.location.start.offset;
sampleId = sampleId.toLowerCase();
var width = $1;
var height = $2;
var screenshotUrl = $3;
Expand Down
2 changes: 1 addition & 1 deletion kumascript/macros/page.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
var url = web.spacesToUnderscores($0);
if ($1) {
$1 = web.spacesToUnderscores($1);
$1 = web.spacesToUnderscores($1).toLowerCase();
}
%>
<%- await wiki.page(url, $1, $2, $3, $4) %>
44 changes: 35 additions & 9 deletions kumascript/src/api/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ const cheerio = require("cheerio");

const H1_TO_H6_TAGS = new Set(["h1", "h2", "h3", "h4", "h5", "h6"]);
const HEADING_TAGS = new Set([...H1_TO_H6_TAGS, "hgroup"]);
const INJECT_SECTION_ID_TAGS = new Set([...HEADING_TAGS, "section"]);
const INJECT_SECTION_ID_TAGS = new Set([
...HEADING_TAGS,
"section",
"div",
"dt",
]);
const LIVE_SAMPLE_PARTS = ["html", "css", "js"];
const SECTION_ID_DISALLOWED = /["#$%&+,/:;=?@[\]^`{|}~')(\\]/g;

Expand Down Expand Up @@ -168,31 +173,52 @@ class HTMLTool {
// If it already has an ID, leave it and use that.
// If it's a H1-6 tag, generate (slugify) an ID from its text.
// If all else, generate a unique one.
// And we ensure all IDs that get added are completely lowercase.
$([...INJECT_SECTION_ID_TAGS].join(",")).each((i, element) => {
const $element = $(element);
const isDt = $element[0].name === "dt";
// Default is the existing one. Let's see if we need to change it.
let id = $element.attr("id");
if ($element.attr("name")) {
// The "name" attribute overrides any current "id".
id = slugify($element.attr("name"));
id = slugify($element.attr("name").toLowerCase());
} else if (id) {
// If it already has an ID, respect it and leave it be.
} else if (H1_TO_H6_TAGS.has($element[0].name)) {
// For heading tags, we'll give them an "id" that's a
// slugified version of their text content.
const text = $element.text();
id = slugify(text);
// If there’s already has an ID, use it — and lowercase it as long
// as the value isn’t "Quick_links" (which we need to keep as-is),
// and as long as it’s not a class=bc-data div (the ID for which we
// need to keep as-is).
if (
id !== "Quick_links" &&
$element[0].attribs["class"] !== "bc-data"
) {
id = id.toLowerCase();
}
} else if (H1_TO_H6_TAGS.has($element[0].name) || isDt) {
// For heading elements, we start by getting the text content of
// the entire heading element (including any children it may have).
let text = $element.text();
if (isDt) {
// dt elements can, along with the actual term, contain stuff
// like <span class="badge inline optional">Optional</span>. If
// we include the text from that, we end up with generated IDs
// like id="rtcSessionDescriptionInit_Optional". So, for dt, we
// take just the text from the first element child of the dt.
text = $element.contents().first().text();
}
id = slugify(text).toLowerCase();
if (id) {
// Ensure that the slugified "id" has not already been
// taken. If it has, create a unique version of it.
let version = 2;
const originalID = id;
while (knownIDs.has(id)) {
id = `${originalID}_${version++}`;
id = `${originalID}_${version++}`.toLowerCase();
}
}
}
if (!id) {
// No need to call toLowerCase() here, because generateUniqueID()
// makes all-lowercase IDs in the form sectN, where N is a number.
id = generateUniqueID();
}
knownIDs.add(id);
Expand Down
76 changes: 38 additions & 38 deletions kumascript/tests/macros/EmbedLiveSample.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ describeMacro("EmbedLiveSample", function () {
macro.call("Quotations"),
'<iframe class="sample-code-frame"' +
' title="Quotations sample"' +
' id="frame_Quotations"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/HTML/Element/figure/_sample_.Quotations.html">' +
' id="frame_quotations"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/HTML/Element/figure/_sample_.quotations.html">' +
"</iframe>"
);
});
Expand All @@ -32,8 +32,8 @@ describeMacro("EmbedLiveSample", function () {
macro.call("SVG_&lt;switch&gt;_example"),
'<iframe class="sample-code-frame"' +
' title="SVG &amp;lt;switch&amp;gt; example sample"' +
' id="frame_SVG_ltswitchgt_example"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/SVG/Element/switch/_sample_.SVG_ltswitchgt_example.html">' +
' id="frame_svg_ltswitchgt_example"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/SVG/Element/switch/_sample_.svg_ltswitchgt_example.html">' +
"</iframe>"
);
});
Expand All @@ -43,8 +43,8 @@ describeMacro("EmbedLiveSample", function () {
macro.call("SVG_%3Cswitch%3E_example"),
'<iframe class="sample-code-frame"' +
' title="SVG %3Cswitch%3E example sample"' +
' id="frame_SVG_switch_example"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/SVG/Element/switch/_sample_.SVG_switch_example.html">' +
' id="frame_svg_switch_example"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/SVG/Element/switch/_sample_.svg_switch_example.html">' +
"</iframe>"
);
});
Expand All @@ -55,8 +55,8 @@ describeMacro("EmbedLiveSample", function () {
macro.call("Dégradés_linéaires_simples"),
'<iframe class="sample-code-frame"' +
' title="Dégradés linéaires simples sample"' +
' id="frame_Dégradés_linéaires_simples"' +
' src="https://mdn.mozillademos.org/fr/docs/Web/CSS/Utilisation_de_d%C3%A9grad%C3%A9s_CSS/_sample_.D%C3%A9grad%C3%A9s_lin%C3%A9aires_simples.html">' +
' id="frame_dégradés_linéaires_simples"' +
' src="https://mdn.mozillademos.org/fr/docs/Web/CSS/Utilisation_de_d%C3%A9grad%C3%A9s_CSS/_sample_.d%C3%A9grad%C3%A9s_lin%C3%A9aires_simples.html">' +
"</iframe>"
);
});
Expand All @@ -66,8 +66,8 @@ describeMacro("EmbedLiveSample", function () {
macro.call('"><script>alert("XSS");</script>'),
'<iframe class="sample-code-frame"' +
' title="&#34;&gt;&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt; sample"' +
' id="frame_scriptalertXSSscript"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/HTML/Element/figure/_sample_.scriptalertXSSscript.html">' +
' id="frame_scriptalertxssscript"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/HTML/Element/figure/_sample_.scriptalertxssscript.html">' +
"</iframe>"
);
});
Expand All @@ -77,9 +77,9 @@ describeMacro("EmbedLiveSample", function () {
macro.call("Example", "100%"),
'<iframe class="sample-code-frame"' +
' title="Example sample"' +
' id="frame_Example"' +
' id="frame_example"' +
' width="100%"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/border-top-width/_sample_.Example.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/border-top-width/_sample_.example.html">' +
"</iframe>"
);
});
Expand All @@ -89,9 +89,9 @@ describeMacro("EmbedLiveSample", function () {
macro.call("Example", '"><script>alert("XSS");</script>'),
'<iframe class="sample-code-frame"' +
' title="Example sample"' +
' id="frame_Example"' +
' id="frame_example"' +
' width="&#34;&gt;&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/border-top-width/_sample_.Example.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/border-top-width/_sample_.example.html">' +
"</iframe>"
);
});
Expand All @@ -101,9 +101,9 @@ describeMacro("EmbedLiveSample", function () {
macro.call("Images", "100%", 250),
'<iframe class="sample-code-frame"' +
' title="Images sample"' +
' id="frame_Images"' +
' id="frame_images"' +
' width="100%" height="250"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/HTML/Element/figure/_sample_.Images.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/HTML/Element/figure/_sample_.images.html">' +
"</iframe>"
);
});
Expand Down Expand Up @@ -142,9 +142,9 @@ describeMacro("EmbedLiveSample", function () {
macro.call("Images", "100%", '"><script>alert("XSS");</script>'),
'<iframe class="sample-code-frame"' +
' title="Images sample"' +
' id="frame_Images"' +
' id="frame_images"' +
' width="100%" height="&#34;&gt;&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/HTML/Element/figure/_sample_.Images.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/HTML/Element/figure/_sample_.images.html">' +
"</iframe>"
);
});
Expand All @@ -154,9 +154,9 @@ describeMacro("EmbedLiveSample", function () {
macro.call("Adding_quotation_marks", "500", "50", ""),
'<iframe class="sample-code-frame"' +
' title="Adding quotation marks sample"' +
' id="frame_Adding_quotation_marks"' +
' id="frame_adding_quotation_marks"' +
` width="500" height="${MIN_HEIGHT}"` +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/::before/_sample_.Adding_quotation_marks.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/::before/_sample_.adding_quotation_marks.html">' +
"</iframe>"
);
});
Expand All @@ -178,9 +178,9 @@ describeMacro("EmbedLiveSample", function () {
"</td><td>" +
'<iframe class="sample-code-frame"' +
' title="SVGLinearGradient sample"' +
' id="frame_SVGLinearGradient"' +
' id="frame_svglineargradient"' +
' width="120" height="240"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/SVG/Tutorial/Gradients/_sample_.SVGLinearGradient.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/SVG/Tutorial/Gradients/_sample_.svglineargradient.html">' +
"</iframe></td></tr></tbody></table>"
);
});
Expand All @@ -204,19 +204,19 @@ describeMacro("EmbedLiveSample", function () {
"</td><td>" +
'<iframe class="sample-code-frame"' +
' title="SVGLinearGradient sample"' +
' id="frame_SVGLinearGradient"' +
' id="frame_svglineargradient"' +
' width="120" height="240"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/SVG/Tutorial/Gradients/_sample_.SVGLinearGradient.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/SVG/Tutorial/Gradients/_sample_.svglineargradient.html">' +
"</iframe></td></tr></tbody></table>"
);
}
);
const same_slug_iframe =
'<iframe class="sample-code-frame"' +
' title="Examples sample"' +
' id="frame_Examples"' +
' id="frame_examples"' +
' width="700px" height="700px"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/flex-wrap/_sample_.Examples.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/flex-wrap/_sample_.examples.html">' +
"</iframe>";
itMacro('Five arguments: ID, width, height, "", same slug', function (macro) {
macro.ctx.env.url = "/en-US/docs/Web/CSS/flex-wrap";
Expand All @@ -241,8 +241,8 @@ describeMacro("EmbedLiveSample", function () {
macro.call("Event delegation", "", "", "", "Web/Events/blur"),
'<iframe class="sample-code-frame"' +
' title="Event delegation sample"' +
' id="frame_Event_delegation"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/Events/blur/_sample_.Event_delegation.html">' +
' id="frame_event_delegation"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/Events/blur/_sample_.event_delegation.html">' +
"</iframe>"
);
});
Expand Down Expand Up @@ -273,8 +273,8 @@ describeMacro("EmbedLiveSample", function () {
),
'<iframe class="sample-code-frame"' +
' title="Event delegation sample"' +
' id="frame_Event_delegation"' +
' src="https://mdn.mozillademos.org/en-US/docs/%22%3E%3Cscript%3Ealert(%22XSS%22);%3C/script%3E/_sample_.Event_delegation.html">' +
' id="frame_event_delegation"' +
' src="https://mdn.mozillademos.org/en-US/docs/%22%3E%3Cscript%3Ealert(%22XSS%22);%3C/script%3E/_sample_.event_delegation.html">' +
"</iframe>"
);
}
Expand All @@ -285,9 +285,9 @@ describeMacro("EmbedLiveSample", function () {
macro.call("sampleNone", 100, 50, "", "", "nobutton"),
'<iframe class="nobutton"' +
' title="sampleNone sample"' +
' id="frame_sampleNone"' +
' id="frame_samplenone"' +
` width="100" height="${MIN_HEIGHT}"` +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/-moz-appearance/_sample_.sampleNone.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/-moz-appearance/_sample_.samplenone.html">' +
"</iframe>"
);
});
Expand All @@ -306,9 +306,9 @@ describeMacro("EmbedLiveSample", function () {
),
'<iframe class="&#34;&gt;&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;"' +
' title="sampleNone sample"' +
' id="frame_sampleNone"' +
' id="frame_samplenone"' +
` width="100" height="${MIN_HEIGHT}"` +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/-moz-appearance/_sample_.sampleNone.html">' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/CSS/-moz-appearance/_sample_.samplenone.html">' +
"</iframe>"
);
}
Expand All @@ -329,9 +329,9 @@ describeMacro("EmbedLiveSample", function () {
),
'<iframe class="sample-code-frame"' +
' title="Example Constraint exerciser sample"' +
' id="frame_Example_Constraint_exerciser"' +
' id="frame_example_constraint_exerciser"' +
' width="650" height="800"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/API/Media_Streams_API/Constraints/_sample_.Example_Constraint_exerciser.html"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/API/Media_Streams_API/Constraints/_sample_.example_constraint_exerciser.html"' +
' allow="video; microphone">' +
"</iframe>"
);
Expand All @@ -353,9 +353,9 @@ describeMacro("EmbedLiveSample", function () {
),
'<iframe class="sample-code-frame"' +
' title="Example Constraint exerciser sample"' +
' id="frame_Example_Constraint_exerciser"' +
' id="frame_example_constraint_exerciser"' +
' width="650" height="800"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/API/Media_Streams_API/Constraints/_sample_.Example_Constraint_exerciser.html"' +
' src="https://mdn.mozillademos.org/en-US/docs/Web/API/Media_Streams_API/Constraints/_sample_.example_constraint_exerciser.html"' +
' allow="&#34;&gt;&lt;script&gt;alert(&#34;XSS&#34;);&lt;/script&gt;">' +
"</iframe>"
);
Expand Down
26 changes: 13 additions & 13 deletions testing/tests/headless.index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ test.describe("Basic viewing of functional pages", () => {
page,
}) => {
const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction";
const flexSample1Uri = `${uri}/Flex/_sample_.Flex_1.html`;
const flexSample2Uri = `${uri}/Flex/_sample_.Flex_2.html`;
const gridSample1Uri = `${uri}/Grid/_sample_.Grid_1.html`;
const gridSample2Uri = `${uri}/_sample_.Grid_2.html`;
const flexSample1Uri = `${uri}/Flex/_sample_.flex_1.html`;
const flexSample2Uri = `${uri}/Flex/_sample_.flex_2.html`;
const gridSample1Uri = `${uri}/Grid/_sample_.grid_1.html`;
const gridSample2Uri = `${uri}/_sample_.grid_2.html`;
await page.goto(testURL(uri));
expect(await page.title()).toContain("A Test Introduction to CSS layout");
expect(await page.innerText("h1")).toBe(
Expand All @@ -62,7 +62,7 @@ test.describe("Basic viewing of functional pages", () => {
expect(
await page.isVisible(`iframe.sample-code-frame[src$="${gridSample1Uri}"]`)
).toBeTruthy();
expect(await page.innerText("#Grid_2 pre.css.notranslate")).toMatch(
expect(await page.innerText("#grid_2 pre.css.notranslate")).toMatch(
/\.wrapper\s*\{\s*display:\s*grid;/
);
expect(
Expand All @@ -89,8 +89,8 @@ test.describe("Basic viewing of functional pages", () => {
page,
}) => {
const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction/Flex";
const flexSample1Uri = `${uri}/_sample_.Flex_1.html`;
const flexSample2Uri = `${uri}/_sample_.Flex_2.html`;
const flexSample1Uri = `${uri}/_sample_.flex_1.html`;
const flexSample2Uri = `${uri}/_sample_.flex_2.html`;
await page.goto(testURL(uri));
expect(await page.title()).toContain(
"A Test Introduction to CSS Flexbox Layout"
Expand All @@ -100,14 +100,14 @@ test.describe("Basic viewing of functional pages", () => {
);
expect(await page.innerText("#flexbox")).toBe("Flexbox");

expect(await page.innerText("#Flex_1 pre.css.notranslate")).toMatch(
expect(await page.innerText("#flex_1 pre.css.notranslate")).toMatch(
/\.wrapper\s*\{\s*display:\s*flex;\s*\}/
);
expect(
await page.isVisible(`iframe.sample-code-frame[src$="${flexSample1Uri}"]`)
).toBeTruthy();

expect(await page.innerText("#Flex_2 pre.css.notranslate")).toMatch(
expect(await page.innerText("#flex_2 pre.css.notranslate")).toMatch(
/\.wrapper {\s*display: flex;\s*\}\s*\.wrapper > div \{\s*flex: 1;\s*\}/
);
expect(
Expand All @@ -119,8 +119,8 @@ test.describe("Basic viewing of functional pages", () => {
page,
}) => {
const uri = "/en-US/docs/Learn/CSS/CSS_layout/Introduction/Grid";
const gridSample1Uri = `${uri}/_sample_.Grid_1.html`;
const gridSample2Uri = `${uri}/_sample_.Grid_2.html`;
const gridSample1Uri = `${uri}/_sample_.grid_1.html`;
const gridSample2Uri = `${uri}/_sample_.grid_2.html`;
await page.goto(testURL(uri));
expect(await page.title()).toContain(
"A Test Introduction to CSS Grid Layout"
Expand All @@ -129,14 +129,14 @@ test.describe("Basic viewing of functional pages", () => {
"A Test Introduction to CSS Grid Layout"
);
expect(await page.innerText("#grid_layout")).toBe("Grid Layout");
expect(await page.innerText("#Grid_1 pre.css.notranslate")).toMatch(
expect(await page.innerText("#grid_1 pre.css.notranslate")).toMatch(
/\.wrapper\s*\{\s*display:\s*grid;/
);
expect(
await page.isVisible(`iframe.sample-code-frame[src$="${gridSample1Uri}"]`)
).toBeTruthy();

expect(await page.innerText("#Grid_2 pre.css.notranslate")).toMatch(
expect(await page.innerText("#grid_2 pre.css.notranslate")).toMatch(
/grid-template-columns: 1fr 1fr 1fr;/
);
expect(
Expand Down

0 comments on commit f1aedef

Please sign in to comment.