@govtechsg/oobee 0.10.69 → 0.10.72
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/DETAILS.md +0 -1
- package/README.md +13 -1
- package/S3_UPLOAD_README.md +172 -0
- package/dev/runGenerateJustHtmlReport.ts +25 -0
- package/package.json +4 -2
- package/src/combine.ts +71 -14
- package/src/constants/common.ts +89 -91
- package/src/constants/constants.ts +535 -60
- package/src/crawlers/crawlDomain.ts +313 -305
- package/src/crawlers/crawlIntelligentSitemap.ts +24 -18
- package/src/crawlers/crawlLocalFile.ts +31 -25
- package/src/crawlers/crawlSitemap.ts +264 -253
- package/src/crawlers/custom/utils.ts +809 -119
- package/src/crawlers/guards/urlGuard.ts +77 -0
- package/src/crawlers/runCustom.ts +32 -4
- package/src/generateHtmlReport.ts +224 -0
- package/src/mergeAxeResults.ts +94 -44
- package/src/runGenerateJustHtmlReport.ts +20 -0
- package/src/services/s3Uploader.ts +184 -0
- package/src/static/ejs/partials/components/allIssues/AllIssues.ejs +9 -0
- package/src/static/ejs/partials/components/allIssues/CategoryBadges.ejs +82 -0
- package/src/static/ejs/partials/components/allIssues/FilterBar.ejs +33 -0
- package/src/static/ejs/partials/components/allIssues/IssuesTable.ejs +41 -0
- package/src/static/ejs/partials/components/header/SiteInfo.ejs +119 -0
- package/src/static/ejs/partials/components/header/aboutScanModal/AboutScanModal.ejs +15 -0
- package/src/static/ejs/partials/components/header/aboutScanModal/ScanConfiguration.ejs +44 -0
- package/src/static/ejs/partials/components/header/aboutScanModal/ScanDetails.ejs +142 -0
- package/src/static/ejs/partials/components/prioritiseIssues/IssueDetailCard.ejs +36 -0
- package/src/static/ejs/partials/components/prioritiseIssues/PrioritiseIssues.ejs +47 -0
- package/src/static/ejs/partials/components/ruleModal/ruleOffcanvas.ejs +196 -0
- package/src/static/ejs/partials/components/scannedPagesSegmentedTabs.ejs +48 -0
- package/src/static/ejs/partials/components/shared/InfoAlert.ejs +3 -0
- package/src/static/ejs/partials/components/{topFive.ejs → topTen.ejs} +2 -2
- package/src/static/ejs/partials/components/wcagCompliance/FailedCriteria.ejs +47 -0
- package/src/static/ejs/partials/components/wcagCompliance/WcagCompliance.ejs +16 -0
- package/src/static/ejs/partials/components/wcagCompliance/WcagGaugeBar.ejs +16 -0
- package/src/static/ejs/partials/components/wcagCoverageDetails.ejs +18 -0
- package/src/static/ejs/partials/footer.ejs +1 -1
- package/src/static/ejs/partials/header.ejs +7 -223
- package/src/static/ejs/partials/main.ejs +12 -23
- package/src/static/ejs/partials/scripts/allIssues/AllIssues.ejs +376 -0
- package/src/static/ejs/partials/scripts/categorySummary.ejs +1 -1
- package/src/static/ejs/partials/scripts/header/SiteInfo.ejs +44 -0
- package/src/static/ejs/partials/scripts/header/aboutScanModal/AboutScanModal.ejs +51 -0
- package/src/static/ejs/partials/scripts/header/aboutScanModal/ScanConfiguration.ejs +127 -0
- package/src/static/ejs/partials/scripts/header/aboutScanModal/ScanDetails.ejs +60 -0
- package/src/static/ejs/partials/scripts/prioritiseIssues/IssueDetailCard.ejs +137 -0
- package/src/static/ejs/partials/scripts/prioritiseIssues/PrioritiseIssues.ejs +214 -0
- package/src/static/ejs/partials/scripts/prioritiseIssues/wcagSvgMap.ejs +861 -0
- package/src/static/ejs/partials/scripts/ruleModal/constants.ejs +949 -0
- package/src/static/ejs/partials/scripts/ruleModal/itemCardRenderer.ejs +352 -0
- package/src/static/ejs/partials/scripts/ruleModal/pageAccordionBuilder.ejs +468 -0
- package/src/static/ejs/partials/scripts/ruleModal/ruleOffcanvas.ejs +306 -0
- package/src/static/ejs/partials/scripts/ruleModal/utilities.ejs +483 -0
- package/src/static/ejs/partials/scripts/scannedPagesSegmentedTabs.ejs +35 -0
- package/src/static/ejs/partials/scripts/screenshotLightbox.ejs +61 -57
- package/src/static/ejs/partials/scripts/topTen.ejs +61 -0
- package/src/static/ejs/partials/scripts/utils.ejs +15 -0
- package/src/static/ejs/partials/scripts/wcagCompliance/FailedCriteria.ejs +103 -0
- package/src/static/ejs/partials/scripts/wcagCompliance/WcagGaugeBar.ejs +47 -0
- package/src/static/ejs/partials/scripts/wcagCompliance.ejs +15 -0
- package/src/static/ejs/partials/scripts/wcagCoverageDetails.ejs +75 -0
- package/src/static/ejs/partials/styles/allIssues/AllIssues.ejs +384 -0
- package/src/static/ejs/partials/styles/bootstrap.ejs +17 -1
- package/src/static/ejs/partials/styles/header/SiteInfo.ejs +121 -0
- package/src/static/ejs/partials/styles/header/aboutScanModal/AboutScanModal.ejs +82 -0
- package/src/static/ejs/partials/styles/header/aboutScanModal/ScanConfiguration.ejs +50 -0
- package/src/static/ejs/partials/styles/header/aboutScanModal/ScanDetails.ejs +149 -0
- package/src/static/ejs/partials/styles/header.ejs +7 -0
- package/src/static/ejs/partials/styles/prioritiseIssues/IssueDetailCard.ejs +141 -0
- package/src/static/ejs/partials/styles/prioritiseIssues/PrioritiseIssues.ejs +204 -0
- package/src/static/ejs/partials/styles/ruleModal/ruleOffcanvas.ejs +456 -0
- package/src/static/ejs/partials/styles/scannedPagesSegmentedTabs.ejs +46 -0
- package/src/static/ejs/partials/styles/shared/InfoAlert.ejs +12 -0
- package/src/static/ejs/partials/styles/styles.ejs +198 -470
- package/src/static/ejs/partials/styles/topTenCard.ejs +44 -0
- package/src/static/ejs/partials/styles/wcagCompliance/FailedCriteria.ejs +59 -0
- package/src/static/ejs/partials/styles/wcagCompliance/WcagGaugeBar.ejs +62 -0
- package/src/static/ejs/partials/styles/wcagCompliance.ejs +36 -0
- package/src/static/ejs/partials/styles/wcagCoverageDetails.ejs +33 -0
- package/src/static/ejs/report.ejs +42 -259
- package/src/static/ejs/summary.ejs +1 -1
- package/src/utils.ts +30 -0
- package/src/static/ejs/partials/components/categorySelector.ejs +0 -4
- package/src/static/ejs/partials/components/categorySelectorDropdown.ejs +0 -57
- package/src/static/ejs/partials/components/pagesScannedModal.ejs +0 -70
- package/src/static/ejs/partials/components/reportSearch.ejs +0 -47
- package/src/static/ejs/partials/components/ruleOffcanvas.ejs +0 -105
- package/src/static/ejs/partials/components/scanAbout.ejs +0 -328
- package/src/static/ejs/partials/components/wcagCompliance.ejs +0 -52
- package/src/static/ejs/partials/scripts/categorySelectorDropdownScript.ejs +0 -190
- package/src/static/ejs/partials/scripts/reportSearch.ejs +0 -287
- package/src/static/ejs/partials/scripts/ruleOffcanvas.ejs +0 -804
- package/src/static/ejs/partials/scripts/scanAboutScript.ejs +0 -38
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
<%- include('./utilities') %> <%- include('./itemCardRenderer') %> <%-
|
|
2
|
+
include('./pageAccordionBuilder') %> <%- include('./constants') %>
|
|
3
|
+
|
|
4
|
+
<script>
|
|
5
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
6
|
+
const modal = document.getElementById('expandedRule');
|
|
7
|
+
if (!modal) return;
|
|
8
|
+
|
|
9
|
+
modal.addEventListener('hidden.bs.modal', function () {
|
|
10
|
+
const openCollapses = modal.querySelectorAll('.accordion-collapse.show');
|
|
11
|
+
openCollapses.forEach(collapseEl => {
|
|
12
|
+
collapseEl.classList.remove('show');
|
|
13
|
+
collapseEl.style.height = '';
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const accordionButtons = modal.querySelectorAll('.accordion-button');
|
|
17
|
+
accordionButtons.forEach(button => {
|
|
18
|
+
button.classList.add('collapsed');
|
|
19
|
+
button.setAttribute('aria-expanded', 'false');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
function populateStepByStepGuide(ruleId) {
|
|
25
|
+
const container = document.getElementById('stepByStepContainer');
|
|
26
|
+
if (!container) return;
|
|
27
|
+
|
|
28
|
+
const steps = stepByStepGuide[ruleId];
|
|
29
|
+
|
|
30
|
+
if (!steps) {
|
|
31
|
+
// No step-by-step guide available for this rule
|
|
32
|
+
container.innerHTML = `
|
|
33
|
+
<div class="no-steps-message">
|
|
34
|
+
<p>Step-by-step guide not yet available for this issue.</p>
|
|
35
|
+
</div>
|
|
36
|
+
`;
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Convert A11y Playground text to link
|
|
41
|
+
const linkifyA11yPlayground = (text) => {
|
|
42
|
+
const escaped = htmlEscapeString(text);
|
|
43
|
+
return escaped.replace(
|
|
44
|
+
/A11y Playground/g,
|
|
45
|
+
`<a href="${a11yPlaygroundLink}" target="_blank" rel="noopener noreferrer">A11y Playground</a>`
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Build the step-by-step HTML
|
|
50
|
+
const stepsHtml = `
|
|
51
|
+
<div class="rule-modal-step">
|
|
52
|
+
<div class="step-header">
|
|
53
|
+
<h4 class="step-title">1. Check</h4>
|
|
54
|
+
</div>
|
|
55
|
+
<div class="step-content">
|
|
56
|
+
<p class="step-text">${linkifyA11yPlayground(steps.check)}</p>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
|
|
60
|
+
<div class="rule-modal-step">
|
|
61
|
+
<div class="step-header">
|
|
62
|
+
<h4 class="step-title">2. Fix</h4>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="step-content">
|
|
65
|
+
<p class="step-text">${linkifyA11yPlayground(steps.fix)}</p>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div class="rule-modal-step">
|
|
70
|
+
<div class="step-header">
|
|
71
|
+
<h4 class="step-title">3. Review</h4>
|
|
72
|
+
</div>
|
|
73
|
+
<div class="step-content">
|
|
74
|
+
<p class="step-text">${linkifyA11yPlayground(steps.review)}</p>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
|
|
78
|
+
<div class="rule-modal-step">
|
|
79
|
+
<div class="step-header">
|
|
80
|
+
<h4 class="step-title">4. Learn</h4>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="step-content">
|
|
83
|
+
<p class="step-text">${linkifyA11yPlayground(steps.learn)}</p>
|
|
84
|
+
</div>
|
|
85
|
+
</div>
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
container.innerHTML = stepsHtml;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function expandRule(selectedCategory, selectedRule) {
|
|
92
|
+
const conformanceLevels = {
|
|
93
|
+
wcag2a: 'A',
|
|
94
|
+
wcag2aa: 'AA',
|
|
95
|
+
wcag21aa: 'AA',
|
|
96
|
+
wcag22aa: 'AA',
|
|
97
|
+
wcag2aaa: 'AAA',
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
const a11yRuleShortDescriptionMap = scanData?.a11yRuleShortDescriptionMap || {};
|
|
101
|
+
const a11yRuleLongDescriptionMap = scanData?.a11yRuleLongDescriptionMap || {};
|
|
102
|
+
const disabilityBadgesMap = scanData?.disabilityBadgesMap || {};
|
|
103
|
+
|
|
104
|
+
// Set image based on WCAG criterion
|
|
105
|
+
const imageElement = document.getElementById('expandedRuleImage');
|
|
106
|
+
const imageContainer = document.getElementById('expandedRuleImageContainer');
|
|
107
|
+
|
|
108
|
+
if (imageElement && imageContainer) {
|
|
109
|
+
let imageSrc = null;
|
|
110
|
+
|
|
111
|
+
// Get the first WCAG criterion from the rule's conformance
|
|
112
|
+
if (selectedRule.conformance && selectedRule.conformance.length > 0) {
|
|
113
|
+
const wcagConformance = selectedRule.conformance.filter(c => c.startsWith('wcag'));
|
|
114
|
+
const wcagCriteriaLabels = scanData?.wcagCriteriaLabels || {};
|
|
115
|
+
|
|
116
|
+
// Find the first matching WCAG criterion
|
|
117
|
+
for (const wcag of wcagConformance) {
|
|
118
|
+
const formattedWcag = formatWcagId(wcag);
|
|
119
|
+
|
|
120
|
+
if (wcagCriteriaLabels[formattedWcag]) {
|
|
121
|
+
// Try to get SVG from the map
|
|
122
|
+
const svg = window.getWcagSvg ? window.getWcagSvg(formattedWcag) : null;
|
|
123
|
+
if (svg) {
|
|
124
|
+
imageSrc = window.svgToDataUrl ? window.svgToDataUrl(svg) : svg;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Hide image container if no SVG found, otherwise show it
|
|
132
|
+
if (!imageSrc) {
|
|
133
|
+
imageContainer.style.display = 'none';
|
|
134
|
+
} else {
|
|
135
|
+
imageContainer.style.display = 'flex';
|
|
136
|
+
imageElement.src = imageSrc;
|
|
137
|
+
imageElement.alt = selectedRule.description || 'Issue illustration';
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Set title from a11yRuleShortDescriptionMap
|
|
142
|
+
const titleElement = document.getElementById('expandedRuleName');
|
|
143
|
+
if (titleElement) {
|
|
144
|
+
const shortDescription = a11yRuleShortDescriptionMap[selectedRule.rule];
|
|
145
|
+
titleElement.textContent = shortDescription || selectedRule.description || '';
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Set category badge
|
|
149
|
+
const categoryBadge = document.getElementById('expandedRuleCategoryBadge');
|
|
150
|
+
if (categoryBadge) {
|
|
151
|
+
const categoryLabels = {
|
|
152
|
+
mustFix: 'Must Fix',
|
|
153
|
+
goodToFix: 'Good to Fix',
|
|
154
|
+
needsReview: 'Manual Test',
|
|
155
|
+
passed: 'Passed',
|
|
156
|
+
};
|
|
157
|
+
categoryBadge.textContent = categoryLabels[selectedCategory] || 'Must Fix';
|
|
158
|
+
|
|
159
|
+
// Update badge class
|
|
160
|
+
categoryBadge.className = 'mustfix-badge-label';
|
|
161
|
+
if (selectedCategory === 'goodToFix') {
|
|
162
|
+
categoryBadge.style.background = 'var(--strong-orange)';
|
|
163
|
+
categoryBadge.style.borderColor = 'var(--strong-orange)';
|
|
164
|
+
} else if (selectedCategory === 'needsReview') {
|
|
165
|
+
categoryBadge.style.background = 'var(--very-dark-gray)';
|
|
166
|
+
categoryBadge.style.borderColor = 'var(--very-dark-gray)';
|
|
167
|
+
} else if (selectedCategory === 'mustFix') {
|
|
168
|
+
categoryBadge.style.background = 'var(--light-carmine-pink)';
|
|
169
|
+
categoryBadge.style.borderColor = 'var(--light-carmine-pink)';
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Update Manual Test Section
|
|
173
|
+
const manualTestSection = document.getElementById('expandedRuleManualTestSection');
|
|
174
|
+
if (selectedCategory === 'needsReview' && manualTestSection) {
|
|
175
|
+
manualTestSection.style.display = 'block';
|
|
176
|
+
} else if (manualTestSection) {
|
|
177
|
+
manualTestSection.style.display = 'none';
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Populate conformance badges
|
|
182
|
+
const conformanceContainer = document.getElementById('expandedRuleConformance');
|
|
183
|
+
if (conformanceContainer && selectedRule.conformance && selectedRule.conformance.length > 0) {
|
|
184
|
+
const wcagConformance = selectedRule.conformance.filter(c => c.startsWith('wcag'));
|
|
185
|
+
const wcagCriteriaLabels = scanData?.wcagCriteriaLabels || {};
|
|
186
|
+
|
|
187
|
+
const criteriaNumbers = [];
|
|
188
|
+
let level = null;
|
|
189
|
+
|
|
190
|
+
wcagConformance.forEach(wcag => {
|
|
191
|
+
const formattedWcag = formatWcagId(wcag);
|
|
192
|
+
|
|
193
|
+
if (wcagCriteriaLabels[formattedWcag]) {
|
|
194
|
+
criteriaNumbers.push(formattedWcag);
|
|
195
|
+
if (!level) {
|
|
196
|
+
level = wcagCriteriaLabels[formattedWcag];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
const badges = criteriaNumbers.map(
|
|
202
|
+
criteria => `<span class="conformance-badge">${criteria}</span>`,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
if (level) {
|
|
206
|
+
badges.push(`<span class="conformance-badge">Level ${level}</span>`);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
conformanceContainer.innerHTML = badges.join('');
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Set long description from a11yRuleLongDescriptionMap
|
|
213
|
+
const longDescriptionElement = document.getElementById('expandedRuleDescription');
|
|
214
|
+
if (longDescriptionElement) {
|
|
215
|
+
const longDescription = a11yRuleLongDescriptionMap[selectedRule.rule];
|
|
216
|
+
longDescriptionElement.textContent = longDescription || whyItMatters[selectedRule.rule] || '';
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Populate disability impact
|
|
220
|
+
const disabilitySection = document.getElementById('expandedRuleDisabilitySection');
|
|
221
|
+
const disabilityMessage = document.getElementById('expandedRuleDisabilityMessage');
|
|
222
|
+
const disabilities = disabilityBadgesMap[selectedRule.rule] || [];
|
|
223
|
+
|
|
224
|
+
if (disabilityMessage && disabilities.length > 0) {
|
|
225
|
+
let disabilityText = '';
|
|
226
|
+
if (disabilities.length === 1) {
|
|
227
|
+
disabilityText = `${disabilities[0]} Disability`;
|
|
228
|
+
} else if (disabilities.length === 2) {
|
|
229
|
+
disabilityText = `${disabilities[0]} and ${disabilities[1]} Disability`;
|
|
230
|
+
} else {
|
|
231
|
+
const disabilityList = [...disabilities];
|
|
232
|
+
const lastDisability = disabilityList.pop();
|
|
233
|
+
disabilityText = `${disabilityList.join(', ')} and ${lastDisability} Disability`;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
disabilityMessage.innerHTML = `This issue prevents users with <span class="disability-text">${disabilityText}</span> from navigating your website.`;
|
|
237
|
+
disabilitySection.style.display = 'block';
|
|
238
|
+
} else {
|
|
239
|
+
disabilitySection.style.display = 'none';
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
if (oobeeAiRules.includes(selectedRule.rule)) {
|
|
243
|
+
document.querySelector('#expandedRuleAiFeedback').style.display = 'block';
|
|
244
|
+
} else {
|
|
245
|
+
document.querySelector('#expandedRuleAiFeedback').style.display = 'none';
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// Populate step-by-step guide
|
|
249
|
+
populateStepByStepGuide(selectedRule.rule);
|
|
250
|
+
|
|
251
|
+
const availableFixCategories = [];
|
|
252
|
+
|
|
253
|
+
const itemsToUse = typeof filteredItems !== 'undefined' ? filteredItems : scanItems;
|
|
254
|
+
|
|
255
|
+
// Reset group by radio buttons to "Page" when modal opens
|
|
256
|
+
const groupByPageRadio = document.getElementById('groupByPage');
|
|
257
|
+
const groupByHtmlRadio = document.getElementById('groupByHtmlElement');
|
|
258
|
+
if (groupByPageRadio && groupByHtmlRadio) {
|
|
259
|
+
groupByPageRadio.checked = true;
|
|
260
|
+
groupByHtmlRadio.checked = false;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Note: Need to check if we want to sort by default in scanItems or keep the function here
|
|
264
|
+
const sortCategoriesByConformance = (items) => {
|
|
265
|
+
['mustFix', 'goodToFix', 'needsReview'].forEach(category => {
|
|
266
|
+
const categoryData = itemsToUse[category];
|
|
267
|
+
if (!categoryData || !Array.isArray(categoryData.rules)) return;
|
|
268
|
+
|
|
269
|
+
categoryData.rules.forEach(rule => {
|
|
270
|
+
if (!Array.isArray(rule.pagesAffected)) return;
|
|
271
|
+
|
|
272
|
+
rule.pagesAffected.sort((a, b) => {
|
|
273
|
+
const lenA = Array.isArray(a.items) ? a.items.length : 0;
|
|
274
|
+
const lenB = Array.isArray(b.items) ? b.items.length : 0;
|
|
275
|
+
return lenB - lenA; // DESC
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
});
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
sortCategoriesByConformance(itemsToUse);
|
|
282
|
+
|
|
283
|
+
Object.keys(itemsToUse).forEach(category => {
|
|
284
|
+
const ruleInCategory = itemsToUse[category]?.rules?.find(r => r.rule === selectedRule.rule);
|
|
285
|
+
|
|
286
|
+
if (ruleInCategory !== undefined && category !== 'passed') {
|
|
287
|
+
if (category !== 'passed') {
|
|
288
|
+
availableFixCategories.push(category);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Automatically display content for the selected category
|
|
292
|
+
if (category === selectedCategory) {
|
|
293
|
+
const occurrencesText = `${ruleInCategory.totalItems} Total occurrences`;
|
|
294
|
+
const dropdownToggle = document.getElementById('expandedRuleDropdownToggleCategoryInfo');
|
|
295
|
+
dropdownToggle.innerText = `${ruleInCategory.totalItems} Total occ.`;
|
|
296
|
+
dropdownToggle.setAttribute('aria-label', occurrencesText);
|
|
297
|
+
document.getElementById('expandedRuleDropdownTitle').innerText =
|
|
298
|
+
`Pages affected by this issue (${ruleInCategory.pagesAffected.length})`;
|
|
299
|
+
buildExpandedRuleCategoryContent(category, ruleInCategory);
|
|
300
|
+
document.getElementById('expandedRulePageContent').innerText =
|
|
301
|
+
`Total ${ruleInCategory.pagesAffected.length} affected pages`;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
</script>
|