Skip to content

Commit

Permalink
fix(routes/html/txt): remove hidden elements (#1830)
Browse files Browse the repository at this point in the history
  • Loading branch information
Fdawgs committed Apr 14, 2024
1 parent 10bc6d4 commit ceb249d
Show file tree
Hide file tree
Showing 12 changed files with 249 additions and 15 deletions.
6 changes: 6 additions & 0 deletions src/plugins/embed-html-images/plugin.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,12 @@ exports[`Embed-HTML-Images plugin Embeds images into HTML 1`] = `
<p class="ft21 c71">sent&nbsp;via&nbsp;email&nbsp;before&nbsp;approval)</p>
<p class="ft20 c72">Notes</p>
</div>
<div style="display: none">
<p>This paragraph should not be displayed.</p>
</div>
<div style="visibility: hidden">
<p>This paragraph should not be visible.</p>
</div>
</body></html>"
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/html-to-txt/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const htmlToTextConfig = {
options: { uppercaseHeaderCells: false },
},
],
wordwrap: null,
wordwrap: false,
};

/**
Expand Down
8 changes: 8 additions & 0 deletions src/plugins/html-to-txt/plugin.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,13 @@ Etiam vehicula luctus fermentum. In vel metus congue, pulvinar lectus vel, ferme
This paragraph should not be displayed.
This paragraph should also not be displayed.
This paragraph should not be visible.
This paragraph should also not be visible.
I am a footer"
`;
30 changes: 30 additions & 0 deletions src/plugins/tidy-css/plugin.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,12 @@ exports[`Tidy-CSS plugin Tidies CSS in HTML 1`] = `
<p class="ft21 c71">sent&nbsp;via&nbsp;email&nbsp;before&nbsp;approval)</p>
<p class="ft20 c72">Notes</p>
</div>
<div style="display: none">
<p>This paragraph should not be displayed.</p>
</div>
<div style="visibility: hidden">
<p>This paragraph should not be visible.</p>
</div>


</body></html>"
Expand Down Expand Up @@ -377,6 +383,12 @@ exports[`Tidy-CSS plugin Tidies CSS in HTML and sets new background color 1`] =
<p class="ft21 c71">sent&nbsp;via&nbsp;email&nbsp;before&nbsp;approval)</p>
<p class="ft20 c72">Notes</p>
</div>
<div style="display: none">
<p>This paragraph should not be displayed.</p>
</div>
<div style="visibility: hidden">
<p>This paragraph should not be visible.</p>
</div>


</body></html>"
Expand Down Expand Up @@ -559,6 +571,12 @@ exports[`Tidy-CSS plugin Tidies CSS in HTML and sets new font 1`] = `
<p class="ft21 c71">sent&nbsp;via&nbsp;email&nbsp;before&nbsp;approval)</p>
<p class="ft20 c72">Notes</p>
</div>
<div style="display: none">
<p>This paragraph should not be displayed.</p>
</div>
<div style="visibility: hidden">
<p>This paragraph should not be visible.</p>
</div>


</body></html>"
Expand Down Expand Up @@ -741,6 +759,12 @@ exports[`Tidy-CSS plugin Tidies CSS in HTML and sets new font in quotation marks
<p class="ft21 c71">sent&nbsp;via&nbsp;email&nbsp;before&nbsp;approval)</p>
<p class="ft20 c72">Notes</p>
</div>
<div style="display: none">
<p>This paragraph should not be displayed.</p>
</div>
<div style="visibility: hidden">
<p>This paragraph should not be visible.</p>
</div>


</body></html>"
Expand Down Expand Up @@ -931,6 +955,12 @@ exports[`Tidy-CSS plugin Tidies CSS in HTML, sets new background color, and sets
<p class="ft21 c71">sent&nbsp;via&nbsp;email&nbsp;before&nbsp;approval)</p>
<p class="ft20 c72">Notes</p>
</div>
<div style="display: none">
<p>This paragraph should not be displayed.</p>
</div>
<div style="visibility: hidden">
<p>This paragraph should not be visible.</p>
</div>


</body></html>"
Expand Down
50 changes: 46 additions & 4 deletions src/plugins/tidy-html/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

const { promisify } = require("node:util");
const fp = require("fastify-plugin");
const { CSSStyleRule, parse: cssomParse } = require("cssom");
const { JSDOM } = require("jsdom");
// @ts-ignore
const { minify } = require("html-minifier-terser");
Expand Down Expand Up @@ -53,6 +54,7 @@ async function plugin(server) {
* @param {boolean} [options.removeAlt] - Set `alt` attributes in `<img>` tags to empty string if set to `true`.
* Useful for sending to clinical systems where img tags are stripped from received documents
* (i.e. TPP's SystmOne), and for screen reader users.
* @param {boolean} [options.removeHidden] - Remove elements with `display: none` or `visibility: hidden` styles if set to `true`.
* @returns {Promise<string>} A promise that resolves with a tidied HTML string, or rejects with an `Error` object
* if `querystring.language` not a valid IANA language tag.
*/
Expand All @@ -73,9 +75,8 @@ async function plugin(server) {
/**
* When an alt attribute is not present in an <img> tag, screen readers may announce the image's file name instead.
* This can be a confusing experience if the file name is not representative of the image's contents.
* As such, alt attributes in <img> tags are set to an empty string rather than removed here.
* @see {@link https://dequeuniversity.com/rules/axe/4.4/image-alt?application=axeAPI | Deque University: Image alt text}
*
* As such, alt attributes in <img> tags are set to an empty string rather than removed here
*/
if (options.removeAlt === true) {
const images = dom.window.document.querySelectorAll("img");
Expand All @@ -86,8 +87,49 @@ async function plugin(server) {
}

/** @type {string} */
const tidiedHtml = await tidyP(dom.serialize(), htmlTidyConfig);
return minify(tidiedHtml, htmlMinifyConfig);
let result = await tidyP(dom.serialize(), htmlTidyConfig);

if (options.removeHidden === true) {
/**
* HTMLTidy2 consolidates inline styles into classes in multiple style tags.
* This simplifies hidden element removal by eliminating parsing of inline
* styles and classes.
*/
const hidden = new JSDOM(result);
const { document } = hidden.window;
const styles = document.querySelectorAll("style");

styles.forEach((style) => {
const styleElement = style;
const styleObj = cssomParse(styleElement.innerHTML);
const cssRulesLength = styleObj.cssRules.length;

for (let i = 0; i < cssRulesLength; i += 1) {
const rule = styleObj.cssRules[i];
if (rule instanceof CSSStyleRule) {
if (
rule.style.display === "none" ||
rule.style.visibility === "hidden"
) {
document
.querySelectorAll(rule.selectorText)
.forEach((element) => {
element.parentNode.removeChild(element);
});
// Remove rule from style tag
styleObj.deleteRule(i);
// Decrement the counter as the length of rules has changed
i -= 1;
}
}
}

styleElement.innerHTML = styleObj.toString();
});
result = hidden.serialize();
}

return minify(result, htmlMinifyConfig);
}

server.decorate("tidyHtml", tidyHtml);
Expand Down
11 changes: 9 additions & 2 deletions src/plugins/tidy-html/plugin.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ describe("Tidy-HTML plugin", () => {
"Tidies HTML, sets img alt attributes to empty string, and sets language",
options: { language: "fr", removeAlt: true },
},
{
testName:
"Tidies HTML and removes elements with `display: none` or `visibility: hidden` styles",
options: { removeHidden: true },
},
])("$testName", async ({ options }) => {
server.post("/", async (req) => server.tidyHtml(req.body, options));
await server.register(sensible).register(plugin).ready();
Expand Down Expand Up @@ -78,8 +83,10 @@ describe("Tidy-HTML plugin", () => {
// Check legacy HTML elements are removed
expect(dom.window.document.querySelector("center")).toBeNull();
expect(dom.window.document.querySelector("font")).toBeNull();
// Check `<![CDATA[]]>` is escaped
expect(dom.window.document.head.textContent).toMatch("/*<![CDATA[*/");
// Check `<![CDATA[]]>` is escaped or removed
expect(dom.window.document.head.textContent).not.toMatch(
/(?<!\/\*)<!\[CDATA\[(?!\*\/)/u
);
// Check HTML comments are removed
expect(dom.window.document.body.textContent).not.toMatch(/<!--|--!?>/u);
// Check HTML is minified
Expand Down

0 comments on commit ceb249d

Please sign in to comment.