fix: Make shared document content available to screenreaders (#9549)

This commit is contained in:
Tom Moor
2025-07-04 16:45:21 -04:00
committed by GitHub
parent 58bfb1b79b
commit 0589f62bde
4 changed files with 45 additions and 1 deletions
+3
View File
@@ -23,6 +23,8 @@ type HTMLOptions = {
includeStyles?: boolean;
/** Whether to include the Mermaid script in the generated HTML (defaults to false) */
includeMermaid?: boolean;
/** Whether to include the doctype,head, etc in the generated HTML (defaults to false) */
includeHead?: boolean;
/** Whether to include styles to center diff (defaults to true) */
centered?: boolean;
/**
@@ -199,6 +201,7 @@ export class DocumentHelper {
title: options?.includeTitle !== false ? document.title : undefined,
includeStyles: options?.includeStyles,
includeMermaid: options?.includeMermaid,
includeHead: options?.includeHead,
centered: options?.centered,
baseUrl: options?.baseUrl,
});
+17 -1
View File
@@ -31,6 +31,8 @@ export type HTMLOptions = {
includeStyles?: boolean;
/** Whether to include mermaidjs scripts in the generated HTML (defaults to false) */
includeMermaid?: boolean;
/** Whether to include head tags in the generated HTML (defaults to true) */
includeHead?: boolean;
/** Whether to include styles to center diff (defaults to true) */
centered?: boolean;
/** The base URL to use for relative links */
@@ -561,7 +563,21 @@ export class ProsemirrorHelper {
dom.window.document.body.appendChild(element);
}
return dom.serialize();
const output = dom.serialize();
if (options?.includeHead === false) {
// replace everything upto and including "<body>"
const body = "<body>";
const bodyIndex = output.indexOf(body) + body.length;
if (bodyIndex !== -1) {
return output
.substring(bodyIndex)
.replace("</body>", "")
.replace("</html>", "");
}
}
return output;
}
/**
+12
View File
@@ -10,6 +10,7 @@ import { unicodeCLDRtoISO639 } from "@shared/utils/date";
import documentLoader from "@server/commands/documentLoader";
import env from "@server/env";
import { Integration } from "@server/models";
import { DocumentHelper } from "@server/models/helpers/DocumentHelper";
import presentEnv from "@server/presenters/env";
import { getTeamFromContext } from "@server/utils/passport";
import prefetchTags from "@server/utils/prefetchTags";
@@ -49,6 +50,7 @@ export const renderApp = async (
options: {
title?: string;
description?: string;
content?: string;
canonical?: string;
shortcutIcon?: string;
rootShareId?: string;
@@ -61,6 +63,7 @@ export const renderApp = async (
title = env.APP_NAME,
description = "A modern team knowledge base for your internal documentation, product specs, support answers, meeting notes, onboarding, &amp; more…",
canonical = "",
content = "",
shortcutIcon = `${env.CDN_URL || ""}/images/favicon-32.png`,
allowIndexing = true,
} = options;
@@ -122,6 +125,7 @@ export const renderApp = async (
.replace(/\{lang\}/g, unicodeCLDRtoISO639(env.DEFAULT_LANGUAGE))
.replace(/\{title\}/g, escape(title))
.replace(/\{description\}/g, escape(description))
.replace(/\{content\}/g, content)
.replace(/\{noindex\}/g, noIndexTag)
.replace(
/\{manifest-url\}/g,
@@ -200,6 +204,14 @@ export const renderShare = async (ctx: Context, next: Next) => {
description:
document?.getSummary() ||
(publicBranding && team?.description ? team.description : undefined),
content: document
? await DocumentHelper.toHTML(document, {
includeStyles: false,
includeHead: false,
includeTitle: true,
signedUrls: true,
})
: undefined,
shortcutIcon:
publicBranding && team?.avatarUrl ? team.avatarUrl : undefined,
analytics,
+13
View File
@@ -49,6 +49,16 @@
min-height: 100%;
width: 100%;
}
.screenreader-only {
clip: rect(0 0 0 0);
clip-path: inset(50%);
height: 1px;
overflow: hidden;
position: absolute;
white-space: nowrap;
width: 1px;
}
</style>
</head>
@@ -63,5 +73,8 @@
}
</script>
{script-tags}
<div class="screenreader-only">
{content}
</div>
</body>
</html>