Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion assets/scss/homepage.scss
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@
display: block;
}

& p#{&}__title {
& strong#{&}__title {
margin-top: 0;
font-size: 1.125em;
font-family: bca6d3310b5c9dae1dae416e8abc8405,helvetica,arial,sans-serif;
Expand Down
4 changes: 2 additions & 2 deletions layouts/shortcodes/blocks/card.html
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
{{ $modifiedSvg := replaceRE `(<svg)(.*?>)` "$1 aria-hidden=\"true\"$2" $svgContent 1 }}
{{ $modifiedSvg | safeHTML }}
</div>
<p class="homepage-card__title">{{ .Title }}</p>
<strong class="homepage-card__title">{{ .Title }}</strong>
{{ if $description }}
<p class="homepage-card__text">{{ $description }}</p>
{{ else }}
Expand All @@ -56,7 +56,7 @@
{{ end }}
</div>
{{ end }}
<p class="homepage-card__title">{{ $title }}</p>
<strong class="homepage-card__title">{{ $title }}</strong>

{{ if eq .Page.File.Ext "md" }}
{{ .Inner | .Page.RenderString }}
Expand Down
117 changes: 75 additions & 42 deletions static/js/ask-ai-accessibility.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
$(document).ready(function () {
let isModalPresent = false;
const $askAiButton = $("#ask-ai-button");
const observedShadowRoots = new WeakSet();

function updateModalState() {
const $kapaContainer = $("#kapa-widget-container");
Expand All @@ -16,10 +17,12 @@ $(document).ready(function () {
if (exists && !isModalPresent) {
isModalPresent = true;
$askAiButton.attr("aria-expanded", "true");
$askAiButton.attr("aria-controls", "kapa-modal-content");
enhanceModalAccessibility(shadowRoot);
} else if (!exists && isModalPresent) {
isModalPresent = false;
$askAiButton.attr("aria-expanded", "false");
$askAiButton.removeAttr("aria-controls");
}
}

Expand Down Expand Up @@ -61,11 +64,12 @@ $(document).ready(function () {
});

// Watch for dynamically added buttons
if (!shadowRoot.getAttribute("data-answer-buttons-observer")) {
shadowRoot.setAttribute("data-answer-buttons-observer", "true");
if (!observedShadowRoots.has(shadowRoot)) {
observedShadowRoots.add(shadowRoot);

const answerButtonsObserver = new MutationObserver(() => {
setupAnswerButtonsAccessibility(shadowRoot);
setupRecaptchaAccessibility(shadowRoot);
});

answerButtonsObserver.observe(shadowRoot, {
Expand All @@ -75,6 +79,72 @@ $(document).ready(function () {
}
}

function setupRecaptchaAccessibility(shadowRoot) {
const recaptchaLink = Array.from(shadowRoot.querySelectorAll("a")).find(a => a.textContent.trim() === "reCAPTCHA");

if (!recaptchaLink) {
return;
}

if (recaptchaLink.hasAttribute("data-recaptcha-a11y-setup")) {
return;
}

recaptchaLink.setAttribute("data-recaptcha-a11y-setup", "true");

// Set proper button semantics since it opens a dialog
recaptchaLink.setAttribute("role", "button");

// Set accessible name
if (!recaptchaLink.getAttribute("aria-label")) {
recaptchaLink.setAttribute("aria-label", "Protected by reCAPTCHA");
}

// Make keyboard accessible
if (!recaptchaLink.hasAttribute("tabindex")) {
recaptchaLink.setAttribute("tabindex", "0");
}

// Setup reCAPTCHA dialog accessibility
recaptchaLink.addEventListener("click", function () {
recaptchaLink.setAttribute("aria-expanded", "true");

setTimeout(() => {
const dialog = shadowRoot.querySelector(".mantine-Popover-dropdown[role='dialog']");
if (dialog) {
const dialogText = dialog.querySelector("p");
if (dialogText && !dialogText.id) {
dialogText.id = "recaptcha-dialog-description";
}

if (!dialog.getAttribute("aria-label")) {
dialog.setAttribute("aria-label", "reCAPTCHA information");
}

if (dialogText && dialogText.id) {
dialog.setAttribute("aria-describedby", dialogText.id);
}

dialog.setAttribute("aria-modal", "true");
dialog.focus();
}
}, 100);
});

// Handle dialog close to update aria-expanded
const closeObserver = new MutationObserver(() => {
const dialog = shadowRoot.querySelector(".mantine-Popover-dropdown[role='dialog']");
if (!dialog) {
recaptchaLink.setAttribute("aria-expanded", "false");
}
});

closeObserver.observe(shadowRoot, {
childList: true,
subtree: true
});
}

function setupDeepThinkingButtonAccessibility(shadowRoot) {
const deepThinkingIcon = shadowRoot.querySelector(".tabler-icon-file-search");
if (!deepThinkingIcon) return;
Expand Down Expand Up @@ -171,12 +241,12 @@ $(document).ready(function () {
}
}

// Style back to top button
// Style send message button (up arrow icon)
const backToTopSvg = shadowRoot.querySelector(".tabler-icon-arrow-up");
if (backToTopSvg) {
const backToTopButton = backToTopSvg.closest("button");
if (backToTopButton && !backToTopButton.getAttribute("aria-label")) {
backToTopButton.setAttribute("aria-label", "Back to top");
backToTopButton.setAttribute("aria-label", "Send message");
if (!backToTopSvg.getAttribute("aria-hidden")) {
backToTopSvg.setAttribute("aria-hidden", "true");
}
Expand All @@ -185,51 +255,14 @@ $(document).ready(function () {

setupDeepThinkingButtonAccessibility(shadowRoot);
setupAnswerButtonsAccessibility(shadowRoot);
setupRecaptchaAccessibility(shadowRoot);

// Fix input accessibility
const kpaInput = shadowRoot.querySelector("#kapa-ask-ai-input");
if (kpaInput) {
kpaInput.setAttribute("aria-label", "Ask me a question about GoodData");
kpaInput.setAttribute("autocomplete", "off");
}

// Fix reCAPTCHA link accessibility
const recaptchaLink = shadowRoot.querySelector("a[data-underline='hover']:not([href])");
if (recaptchaLink && recaptchaLink.textContent.includes("reCAPTCHA")) {
if (!recaptchaLink.getAttribute("aria-label")) {
recaptchaLink.setAttribute("aria-label", "Protected by reCAPTCHA");
}

recaptchaLink.setAttribute("role", "button");

if (!recaptchaLink.hasAttribute("href")) {
recaptchaLink.setAttribute("tabindex", "0");
}

// Setup reCAPTCHA dialog accessibility
recaptchaLink.addEventListener("click", function () {
setTimeout(() => {
const dialog = shadowRoot.querySelector(".mantine-Popover-dropdown[role='dialog']");
if (dialog) {
const dialogText = dialog.querySelector("p");
if (dialogText && !dialogText.id) {
dialogText.id = "recaptcha-dialog-description";
}

if (!dialog.getAttribute("aria-label")) {
dialog.setAttribute("aria-label", "reCAPTCHA information");
}

if (dialogText && dialogText.id) {
dialog.setAttribute("aria-describedby", dialogText.id);
}

dialog.setAttribute("aria-modal", "true");
dialog.focus();
}
}, 100);
});
}
}

setTimeout(function () {
Expand Down
Loading