1+ class QuartoAxeReporter {
2+ constructor ( axeResult , options ) {
3+ this . axeResult = axeResult ;
4+ this . options = options ;
5+ }
6+
7+ report ( ) {
8+ throw new Error ( "report() is an abstract method" ) ;
9+ }
10+ }
11+
12+ class QuartoAxeJsonReporter extends QuartoAxeReporter {
13+ constructor ( axeResult , options ) {
14+ super ( axeResult , options ) ;
15+ }
16+
17+ report ( ) {
18+ console . log ( JSON . stringify ( this . axeResult , null , 2 ) ) ;
19+ }
20+ }
21+
22+ class QuartoAxeConsoleReporter extends QuartoAxeReporter {
23+ constructor ( axeResult , options ) {
24+ super ( axeResult , options ) ;
25+ }
26+
27+ report ( ) {
28+ for ( const violation of this . axeResult . violations ) {
29+ console . log ( violation . description ) ;
30+ for ( const node of violation . nodes ) {
31+ for ( const target of node . target ) {
32+ console . log ( target ) ;
33+ console . log ( document . querySelector ( target ) ) ;
34+ }
35+ }
36+ }
37+ }
38+ }
39+
40+ class QuartoAxeDocumentReporter extends QuartoAxeReporter {
41+ constructor ( axeResult , options ) {
42+ super ( axeResult , options ) ;
43+ }
44+
45+ createViolationElement ( violation ) {
46+ const violationElement = document . createElement ( "div" ) ;
47+
48+ const descriptionElement = document . createElement ( "div" ) ;
49+ descriptionElement . className = "quarto-axe-violation-description" ;
50+ descriptionElement . innerText = `${ violation . impact . replace ( / ^ [ a - z ] / , match => match . toLocaleUpperCase ( ) ) } : ${ violation . description } ` ;
51+ violationElement . appendChild ( descriptionElement ) ;
52+
53+ const helpElement = document . createElement ( "div" ) ;
54+ helpElement . className = "quarto-axe-violation-help" ;
55+ helpElement . innerText = violation . help ;
56+ violationElement . appendChild ( helpElement ) ;
57+
58+ const nodesElement = document . createElement ( "div" ) ;
59+ nodesElement . className = "quarto-axe-violation-nodes" ;
60+ violationElement . appendChild ( nodesElement ) ;
61+ const nodeElement = document . createElement ( "div" ) ;
62+ nodeElement . className = "quarto-axe-violation-selector" ;
63+ for ( const node of violation . nodes ) {
64+ for ( const target of node . target ) {
65+ const targetElement = document . createElement ( "span" ) ;
66+ targetElement . className = "quarto-axe-violation-target" ;
67+ targetElement . innerText = target ;
68+ nodeElement . appendChild ( targetElement ) ;
69+ nodeElement . addEventListener ( "mouseenter" , ( ) => {
70+ const element = document . querySelector ( target ) ;
71+ if ( element ) {
72+ element . scrollIntoView ( { behavior : "smooth" , block : "center" } ) ;
73+ element . classList . add ( "quarto-axe-hover-highlight" ) ;
74+ setTimeout ( ( ) => {
75+ element . style . border = "" ;
76+ } , 2000 ) ;
77+ }
78+ } ) ;
79+ nodeElement . addEventListener ( "mouseleave" , ( ) => {
80+ const element = document . querySelector ( target ) ;
81+ if ( element ) {
82+ element . classList . remove ( "quarto-axe-hover-highlight" ) ;
83+ }
84+ } ) ;
85+ nodeElement . addEventListener ( "click" , ( ) => {
86+ console . log ( document . querySelector ( target ) ) ;
87+ } ) ;
88+ nodeElement . appendChild ( targetElement ) ;
89+ }
90+ nodesElement . appendChild ( nodeElement ) ;
91+ }
92+ return violationElement ;
93+ }
94+
95+ report ( ) {
96+ const violations = this . axeResult . violations ;
97+ const reportElement = document . createElement ( "div" ) ;
98+ reportElement . className = "quarto-axe-report" ;
99+ if ( violations . length === 0 ) {
100+ const noViolationsElement = document . createElement ( "div" ) ;
101+ noViolationsElement . className = "quarto-axe-no-violations" ;
102+ noViolationsElement . innerText = "No axe-core violations found." ;
103+ reportElement . appendChild ( noViolationsElement ) ;
104+ }
105+ violations . forEach ( ( violation ) => {
106+ reportElement . appendChild ( this . createViolationElement ( violation ) ) ;
107+ } ) ;
108+ document . querySelector ( "main" ) . appendChild ( reportElement ) ;
109+ }
110+ }
111+
112+ const reporters = {
113+ json : QuartoAxeJsonReporter ,
114+ console : QuartoAxeConsoleReporter ,
115+ document : QuartoAxeDocumentReporter ,
116+ } ;
117+
118+ class QuartoAxeChecker {
119+ constructor ( opts ) {
120+ this . options = opts ;
121+ }
122+ async init ( ) {
123+ const axe = ( await import ( "https://cdn.skypack.dev/pin/axe-core@v4.10.3-aVOFXWsJaCpVrtv89pCa/mode=imports,min/optimized/axe-core.js" ) ) . default ;
124+ const result = await axe . run ( {
125+ exclude : [
126+ // https://github.com/microsoft/tabster/issues/288
127+ // MS has claimed they won't fix this, so we need to add an exclusion to
128+ // all tabster elements
129+ "[data-tabster-dummy]"
130+ ] ,
131+ preload : { assets : [ 'cssom' ] , timeout : 50000 }
132+ } ) ;
133+ const reporter = this . options === true ? new QuartoAxeConsoleReporter ( result ) : new reporters [ this . options . output ] ( result , this . options ) ;
134+ reporter . report ( ) ;
135+ }
136+ }
137+
138+ export async function init ( ) {
139+ const opts = document . querySelector ( "#quarto-axe-checker-options" ) ;
140+ if ( opts ) {
141+ const jsonOptions = JSON . parse ( atob ( opts . textContent ) ) ;
142+ const checker = new QuartoAxeChecker ( jsonOptions ) ;
143+ await checker . init ( ) ;
144+ }
145+ }
0 commit comments