145 lines
4.8 KiB
JavaScript
145 lines
4.8 KiB
JavaScript
class QuartoAxeReporter {
|
|
constructor(axeResult, options) {
|
|
this.axeResult = axeResult;
|
|
this.options = options;
|
|
}
|
|
|
|
report() {
|
|
throw new Error("report() is an abstract method");
|
|
}
|
|
}
|
|
|
|
class QuartoAxeJsonReporter extends QuartoAxeReporter {
|
|
constructor(axeResult, options) {
|
|
super(axeResult, options);
|
|
}
|
|
|
|
report() {
|
|
console.log(JSON.stringify(this.axeResult, null, 2));
|
|
}
|
|
}
|
|
|
|
class QuartoAxeConsoleReporter extends QuartoAxeReporter {
|
|
constructor(axeResult, options) {
|
|
super(axeResult, options);
|
|
}
|
|
|
|
report() {
|
|
for (const violation of this.axeResult.violations) {
|
|
console.log(violation.description);
|
|
for (const node of violation.nodes) {
|
|
for (const target of node.target) {
|
|
console.log(target);
|
|
console.log(document.querySelector(target));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class QuartoAxeDocumentReporter extends QuartoAxeReporter {
|
|
constructor(axeResult, options) {
|
|
super(axeResult, options);
|
|
}
|
|
|
|
createViolationElement(violation) {
|
|
const violationElement = document.createElement("div");
|
|
|
|
const descriptionElement = document.createElement("div");
|
|
descriptionElement.className = "quarto-axe-violation-description";
|
|
descriptionElement.innerText = `${violation.impact.replace(/^[a-z]/, match => match.toLocaleUpperCase())}: ${violation.description}`;
|
|
violationElement.appendChild(descriptionElement);
|
|
|
|
const helpElement = document.createElement("div");
|
|
helpElement.className = "quarto-axe-violation-help";
|
|
helpElement.innerText = violation.help;
|
|
violationElement.appendChild(helpElement);
|
|
|
|
const nodesElement = document.createElement("div");
|
|
nodesElement.className = "quarto-axe-violation-nodes";
|
|
violationElement.appendChild(nodesElement);
|
|
const nodeElement = document.createElement("div");
|
|
nodeElement.className = "quarto-axe-violation-selector";
|
|
for (const node of violation.nodes) {
|
|
for (const target of node.target) {
|
|
const targetElement = document.createElement("span");
|
|
targetElement.className = "quarto-axe-violation-target";
|
|
targetElement.innerText = target;
|
|
nodeElement.appendChild(targetElement);
|
|
nodeElement.addEventListener("mouseenter", () => {
|
|
const element = document.querySelector(target);
|
|
if (element) {
|
|
element.scrollIntoView({ behavior: "smooth", block: "center" });
|
|
element.classList.add("quarto-axe-hover-highlight");
|
|
setTimeout(() => {
|
|
element.style.border = "";
|
|
}, 2000);
|
|
}
|
|
});
|
|
nodeElement.addEventListener("mouseleave", () => {
|
|
const element = document.querySelector(target);
|
|
if (element) {
|
|
element.classList.remove("quarto-axe-hover-highlight");
|
|
}
|
|
});
|
|
nodeElement.addEventListener("click", () => {
|
|
console.log(document.querySelector(target));
|
|
});
|
|
nodeElement.appendChild(targetElement);
|
|
}
|
|
nodesElement.appendChild(nodeElement);
|
|
}
|
|
return violationElement;
|
|
}
|
|
|
|
report() {
|
|
const violations = this.axeResult.violations;
|
|
const reportElement = document.createElement("div");
|
|
reportElement.className = "quarto-axe-report";
|
|
if (violations.length === 0) {
|
|
const noViolationsElement = document.createElement("div");
|
|
noViolationsElement.className = "quarto-axe-no-violations";
|
|
noViolationsElement.innerText = "No axe-core violations found.";
|
|
reportElement.appendChild(noViolationsElement);
|
|
}
|
|
violations.forEach((violation) => {
|
|
reportElement.appendChild(this.createViolationElement(violation));
|
|
});
|
|
document.querySelector("main").appendChild(reportElement);
|
|
}
|
|
}
|
|
|
|
const reporters = {
|
|
json: QuartoAxeJsonReporter,
|
|
console: QuartoAxeConsoleReporter,
|
|
document: QuartoAxeDocumentReporter,
|
|
};
|
|
|
|
class QuartoAxeChecker {
|
|
constructor(opts) {
|
|
this.options = opts;
|
|
}
|
|
async init() {
|
|
const axe = (await import("https://cdn.skypack.dev/pin/axe-core@v4.10.3-aVOFXWsJaCpVrtv89pCa/mode=imports,min/optimized/axe-core.js")).default;
|
|
const result = await axe.run({
|
|
exclude: [
|
|
// https://github.com/microsoft/tabster/issues/288
|
|
// MS has claimed they won't fix this, so we need to add an exclusion to
|
|
// all tabster elements
|
|
"[data-tabster-dummy]"
|
|
],
|
|
preload: { assets: ['cssom'], timeout: 50000 }
|
|
});
|
|
const reporter = this.options === true ? new QuartoAxeConsoleReporter(result) : new reporters[this.options.output](result, this.options);
|
|
reporter.report();
|
|
}
|
|
}
|
|
|
|
export async function init() {
|
|
const opts = document.querySelector("#quarto-axe-checker-options");
|
|
if (opts) {
|
|
const jsonOptions = JSON.parse(atob(opts.textContent));
|
|
const checker = new QuartoAxeChecker(jsonOptions);
|
|
await checker.init();
|
|
}
|
|
} |