accessibility-checker 4.0.31 → 4.0.32
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/README.md +29 -0
- package/cjs/lib/common/config/ACConfigManager.js +15 -1
- package/cjs/lib/common/config/ACConfigManager.js.map +1 -1
- package/cjs/lib/common/config/ACConstants.js +4 -4
- package/cjs/lib/common/config/ACConstants.js.map +1 -1
- package/cjs/lib/common/report/ACReporterXLSX.d.ts +2 -2
- package/cjs/lib/common/report/ACReporterXLSX.js +408 -649
- package/cjs/lib/common/report/ACReporterXLSX.js.map +1 -1
- package/cjs/lib/common/report/genReport.js +2 -2
- package/cjs/lib/common/report/genReport.js.map +1 -1
- package/lib/common/config/ACConfigManager.js +15 -1
- package/lib/common/config/ACConfigManager.js.map +1 -1
- package/lib/common/config/ACConstants.js +4 -4
- package/lib/common/config/ACConstants.js.map +1 -1
- package/lib/common/report/ACReporterXLSX.d.ts +2 -2
- package/lib/common/report/ACReporterXLSX.js +408 -649
- package/lib/common/report/ACReporterXLSX.js.map +1 -1
- package/lib/common/report/genReport.js +2 -2
- package/lib/common/report/genReport.js.map +1 -1
- package/mjs/lib/common/config/ACConfigManager.js +15 -1
- package/mjs/lib/common/config/ACConfigManager.js.map +1 -1
- package/mjs/lib/common/config/ACConstants.js +4 -4
- package/mjs/lib/common/config/ACConstants.js.map +1 -1
- package/mjs/lib/common/report/ACReporterXLSX.d.ts +2 -2
- package/mjs/lib/common/report/ACReporterXLSX.js +421 -650
- package/mjs/lib/common/report/ACReporterXLSX.js.map +1 -1
- package/mjs/lib/common/report/genReport.js +2 -2
- package/mjs/lib/common/report/genReport.js.map +1 -1
- package/package.json +4 -11
|
@@ -17,24 +17,23 @@ import { eRuleLevel } from "../config/IConfig.js";
|
|
|
17
17
|
import { eToolkitLevel } from "../engine/IGuideline.js";
|
|
18
18
|
import { eRuleConfidence } from "../engine/IRule.js";
|
|
19
19
|
import { ReporterManager } from "./ReporterManager.js";
|
|
20
|
-
// Lazy
|
|
21
|
-
let
|
|
22
|
-
let
|
|
23
|
-
function
|
|
24
|
-
if (!
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
.
|
|
29
|
-
.catch(e => null);
|
|
20
|
+
// Lazy-load write-excel-file — will be null if not installed
|
|
21
|
+
let writeExcelLoadPromise = null;
|
|
22
|
+
let writeExcelWarningShown = false;
|
|
23
|
+
function loadWriteExcel() {
|
|
24
|
+
if (!writeExcelLoadPromise) {
|
|
25
|
+
const moduleName = "write-excel-file/node";
|
|
26
|
+
writeExcelLoadPromise = import(/* webpackIgnore: true */ moduleName)
|
|
27
|
+
.then(module => module.default ?? module)
|
|
28
|
+
.catch(() => null);
|
|
30
29
|
}
|
|
31
|
-
return
|
|
30
|
+
return writeExcelLoadPromise;
|
|
32
31
|
}
|
|
33
|
-
function
|
|
34
|
-
if (!
|
|
35
|
-
|
|
36
|
-
console.warn("Warning:
|
|
37
|
-
console.warn("To enable XLSX reports, install
|
|
32
|
+
function showWriteExcelWarning() {
|
|
33
|
+
if (!writeExcelWarningShown) {
|
|
34
|
+
writeExcelWarningShown = true;
|
|
35
|
+
console.warn("Warning: write-excel-file is not installed. XLSX report generation is disabled.");
|
|
36
|
+
console.warn("To enable XLSX reports, install write-excel-file: npm install write-excel-file");
|
|
38
37
|
}
|
|
39
38
|
}
|
|
40
39
|
function dropDupes(arr) {
|
|
@@ -48,6 +47,121 @@ function dropDupes(arr) {
|
|
|
48
47
|
}
|
|
49
48
|
});
|
|
50
49
|
}
|
|
50
|
+
// Convert ExcelJS-style ARGB (FFRRGGBB) to 6-digit hex (#RRGGBB)
|
|
51
|
+
function argbToHex(argb) {
|
|
52
|
+
if (!argb || argb.length < 6)
|
|
53
|
+
return "#000000";
|
|
54
|
+
// Strip leading alpha if 8 chars
|
|
55
|
+
const rgb = argb.length === 8 ? argb.slice(2) : argb;
|
|
56
|
+
return `#${rgb}`;
|
|
57
|
+
}
|
|
58
|
+
// Helper: cell with dark purple header style
|
|
59
|
+
function headerCell(value, columnSpan) {
|
|
60
|
+
const cell = {
|
|
61
|
+
value,
|
|
62
|
+
backgroundColor: "#403151",
|
|
63
|
+
textColor: "#FFFFFF",
|
|
64
|
+
fontFamily: "Calibri",
|
|
65
|
+
fontSize: 16,
|
|
66
|
+
alignVertical: "center",
|
|
67
|
+
align: "left",
|
|
68
|
+
height: 36,
|
|
69
|
+
};
|
|
70
|
+
if (columnSpan && columnSpan > 1)
|
|
71
|
+
cell.columnSpan = columnSpan;
|
|
72
|
+
return cell;
|
|
73
|
+
}
|
|
74
|
+
// Helper: standard data cell
|
|
75
|
+
function dataCell(value, opts) {
|
|
76
|
+
return {
|
|
77
|
+
value,
|
|
78
|
+
fontFamily: "Calibri",
|
|
79
|
+
fontSize: 12,
|
|
80
|
+
textColor: "#000000",
|
|
81
|
+
...opts
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
// Helper: bordered cell
|
|
85
|
+
function borderedCell(value, opts) {
|
|
86
|
+
return {
|
|
87
|
+
value,
|
|
88
|
+
fontFamily: "Calibri",
|
|
89
|
+
fontSize: 12,
|
|
90
|
+
textColor: "#000000",
|
|
91
|
+
borderColor: "#A6A6A6",
|
|
92
|
+
borderStyle: "thin",
|
|
93
|
+
...opts
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// ─── XLSX table injection ──────────────────────────────────────────────────────
|
|
97
|
+
// write-excel-file has no native Excel table API. We post-process the output
|
|
98
|
+
// file: unzip it with Node's built-in zlib, inject the table definition XML,
|
|
99
|
+
// wire the sheet to reference it, and re-zip.
|
|
100
|
+
//
|
|
101
|
+
// The Issues sheet is always sheet index 3 (0-based) → sheetId "4".
|
|
102
|
+
// TableStyleMedium2 + showRowStripes matches the original ExcelJS output.
|
|
103
|
+
const ISSUES_SHEET_ID = "4";
|
|
104
|
+
const ISSUES_TABLE_ID = "1";
|
|
105
|
+
const ISSUES_COL_COUNT = 14;
|
|
106
|
+
const ISSUES_COL_NAMES = [
|
|
107
|
+
"Page title", "Page URL", "Scan label", "Issue ID", "Issue type",
|
|
108
|
+
"Toolkit level", "Checkpoint", "WCAG level", "Rule", "Issue",
|
|
109
|
+
"Element", "Code", "Xpath", "Help",
|
|
110
|
+
];
|
|
111
|
+
function buildTableXml(rowCount) {
|
|
112
|
+
const lastCol = "ABCDEFGHIJKLMN"[ISSUES_COL_COUNT - 1];
|
|
113
|
+
const ref = `A1:${lastCol}${rowCount}`;
|
|
114
|
+
const cols = ISSUES_COL_NAMES.map((name, i) => `<tableColumn id="${i + 1}" name="${name}"/>`).join("");
|
|
115
|
+
return `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
116
|
+
`<table xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"` +
|
|
117
|
+
` id="${ISSUES_TABLE_ID}" name="IssuesTable" displayName="IssuesTable" ref="${ref}" headerRowCount="1">` +
|
|
118
|
+
`<autoFilter ref="${ref}"/>` +
|
|
119
|
+
`<tableColumns count="${ISSUES_COL_COUNT}">${cols}</tableColumns>` +
|
|
120
|
+
`<tableStyleInfo name="TableStyleMedium2" showFirstColumn="0"` +
|
|
121
|
+
` showLastColumn="0" showRowStripes="1" showColumnStripes="0"/>` +
|
|
122
|
+
`</table>`;
|
|
123
|
+
}
|
|
124
|
+
async function injectTableIntoFile(filePath, issueRowCount) {
|
|
125
|
+
let AdmZip;
|
|
126
|
+
try {
|
|
127
|
+
// webpackIgnore prevents Cypress/webpack from trying to bundle this Node-only module.
|
|
128
|
+
// The try/catch ensures graceful degradation if adm-zip is not installed.
|
|
129
|
+
AdmZip = require(/* webpackIgnore: true */ "adm-zip");
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// adm-zip not available — skip table injection gracefully
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const zip = new AdmZip(filePath);
|
|
136
|
+
// 1. Add xl/tables/table1.xml
|
|
137
|
+
const tableXml = buildTableXml(issueRowCount);
|
|
138
|
+
zip.addFile(`xl/tables/table${ISSUES_TABLE_ID}.xml`, Buffer.from(tableXml, "utf8"));
|
|
139
|
+
// 2. Patch xl/worksheets/_rels/sheet4.xml.rels
|
|
140
|
+
const relsPath = `xl/worksheets/_rels/sheet${ISSUES_SHEET_ID}.xml.rels`;
|
|
141
|
+
const relsEntry = zip.getEntry(relsPath);
|
|
142
|
+
const tableRel = `<Relationship Id="rIdTbl"` +
|
|
143
|
+
` Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/table"` +
|
|
144
|
+
` Target="../tables/table${ISSUES_TABLE_ID}.xml"/>`;
|
|
145
|
+
if (relsEntry) {
|
|
146
|
+
const existing = relsEntry.getData().toString("utf8");
|
|
147
|
+
zip.updateFile(relsPath, Buffer.from(existing.replace("</Relationships>", tableRel + "</Relationships>"), "utf8"));
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
zip.addFile(relsPath, Buffer.from(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?>` +
|
|
151
|
+
`<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">` +
|
|
152
|
+
tableRel + `</Relationships>`, "utf8"));
|
|
153
|
+
}
|
|
154
|
+
// 3. Patch xl/worksheets/sheet4.xml — add <tableParts> before </worksheet>
|
|
155
|
+
const sheetPath = `xl/worksheets/sheet${ISSUES_SHEET_ID}.xml`;
|
|
156
|
+
const sheetXml = zip.getEntry(sheetPath).getData().toString("utf8");
|
|
157
|
+
zip.updateFile(sheetPath, Buffer.from(sheetXml.replace("</worksheet>", `<tableParts count="1"><tablePart r:id="rIdTbl"/></tableParts></worksheet>`), "utf8"));
|
|
158
|
+
// 4. Patch [Content_Types].xml
|
|
159
|
+
const ctPath = "[Content_Types].xml";
|
|
160
|
+
const ctXml = zip.getEntry(ctPath).getData().toString("utf8");
|
|
161
|
+
zip.updateFile(ctPath, Buffer.from(ctXml.replace("</Types>", `<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"` +
|
|
162
|
+
` PartName="/xl/tables/table${ISSUES_TABLE_ID}.xml"/></Types>`), "utf8"));
|
|
163
|
+
zip.writeZip(filePath);
|
|
164
|
+
}
|
|
51
165
|
export class ACReporterXLSX {
|
|
52
166
|
name() {
|
|
53
167
|
return "xlsx";
|
|
@@ -74,7 +188,6 @@ export class ACReporterXLSX {
|
|
|
74
188
|
policyInfo[ruleId].tkLevels = dropDupes(policyInfo[ruleId].tkLevels);
|
|
75
189
|
policyInfo[ruleId].tkLevels.sort();
|
|
76
190
|
}
|
|
77
|
-
// const buffer: any = await workbook.xlsx.writeBuffer();
|
|
78
191
|
let startScan = new Date(storedReport.engineReport.summary.startScan);
|
|
79
192
|
let reportFilename = `results_${startScan.toISOString().replace(/:/g, "-")}.xlsx`;
|
|
80
193
|
if (config.outputFilenameTimestamp === false) {
|
|
@@ -83,34 +196,33 @@ export class ACReporterXLSX {
|
|
|
83
196
|
return {
|
|
84
197
|
summaryPath: reportFilename,
|
|
85
198
|
summary: async (filename) => {
|
|
86
|
-
const
|
|
87
|
-
if (!
|
|
88
|
-
|
|
199
|
+
const writeExcelFile = await loadWriteExcel();
|
|
200
|
+
if (!writeExcelFile) {
|
|
201
|
+
showWriteExcelWarning();
|
|
89
202
|
return;
|
|
90
203
|
}
|
|
91
|
-
|
|
92
|
-
const
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
204
|
+
const issuesSheet = ACReporterXLSX.createIssuesSheet(config, policyInfo, summaryData);
|
|
205
|
+
const issueRowCount = issuesSheet._issueRowCount;
|
|
206
|
+
delete issuesSheet._issueRowCount;
|
|
207
|
+
const sheets = [
|
|
208
|
+
ACReporterXLSX.createOverviewSheet(config, summaryData),
|
|
209
|
+
ACReporterXLSX.createScanSummarySheet(config, summaryData),
|
|
210
|
+
ACReporterXLSX.createIssueSummarySheet(config, policyInfo, summaryData),
|
|
211
|
+
issuesSheet,
|
|
212
|
+
ACReporterXLSX.createDefinitionsSheet(),
|
|
213
|
+
];
|
|
214
|
+
await writeExcelFile(sheets).toFile(filename);
|
|
215
|
+
await injectTableIntoFile(filename, issueRowCount);
|
|
100
216
|
}
|
|
101
217
|
};
|
|
102
218
|
}
|
|
103
|
-
static createOverviewSheet(config, compressedScans
|
|
219
|
+
static createOverviewSheet(config, compressedScans) {
|
|
104
220
|
let violations = 0;
|
|
105
221
|
let needsReviews = 0;
|
|
106
222
|
let recommendations = 0;
|
|
107
223
|
let archived = 0;
|
|
108
224
|
let totalIssues = 0;
|
|
109
225
|
let startScan = 0;
|
|
110
|
-
// BIG QUESTION: is report
|
|
111
|
-
// 1. for current scan (from menu)
|
|
112
|
-
// 2. all stored scans (from menu)
|
|
113
|
-
// 3. selected stored scans (from scan manager)
|
|
114
226
|
for (const compressedScan of compressedScans) {
|
|
115
227
|
let storedScan = ReporterManager.uncompressReport(compressedScan);
|
|
116
228
|
if (startScan === 0)
|
|
@@ -122,311 +234,147 @@ export class ACReporterXLSX {
|
|
|
122
234
|
archived += counts.ignored;
|
|
123
235
|
}
|
|
124
236
|
totalIssues = violations + needsReviews + recommendations + archived;
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
cellA1.value = "Accessibility Scan Report";
|
|
132
|
-
cellA1.alignment = { vertical: "middle", horizontal: "left" };
|
|
133
|
-
cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
|
|
134
|
-
cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
135
|
-
// what are column widths - can't get it till you set it
|
|
136
|
-
const colWidthData = [
|
|
137
|
-
{ col: 'A', width: 15.1 },
|
|
138
|
-
{ col: 'B', width: 15.9 },
|
|
139
|
-
{ col: 'C', width: 16.23 },
|
|
140
|
-
{ col: 'D', width: 19.4 },
|
|
237
|
+
const columns = [
|
|
238
|
+
{ width: 15.1 },
|
|
239
|
+
{ width: 15.9 },
|
|
240
|
+
{ width: 16.23 },
|
|
241
|
+
{ width: 19.4 },
|
|
242
|
+
{ width: 15 },
|
|
141
243
|
];
|
|
142
|
-
for (let i = 0; i < 4; i++) {
|
|
143
|
-
worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
|
|
144
|
-
}
|
|
145
|
-
// note except for Report Date this is the same for all scans
|
|
146
244
|
const rowData = [
|
|
147
245
|
{ key1: 'Tool:', key2: 'IBM Equal Access Accessibility Checker' },
|
|
148
|
-
// {key1: 'Version:', key2: "chrome.runtime.getManifest().version"},
|
|
149
246
|
{ key1: 'Version:', key2: config.toolID },
|
|
150
|
-
//@ts-ignore
|
|
151
|
-
// {key1: 'Rule set:', key2: (theCurrentScan.ruleSet === "Latest Deployment") ? archives[1].name : theCurrentScan.ruleSet },
|
|
152
247
|
{ key1: 'Rule set:', key2: config.ruleArchiveLabel },
|
|
153
248
|
{ key1: 'Guidelines:', key2: config.policies.join(", ") },
|
|
154
|
-
{ key1: 'Report date:', key2: new Date(startScan).toLocaleString() },
|
|
155
|
-
{ key1: 'Scans:', key2: "" + compressedScans.length },
|
|
156
|
-
// { key1: 'Pages:', key2: "" }
|
|
249
|
+
{ key1: 'Report date:', key2: new Date(startScan).toLocaleString() },
|
|
250
|
+
{ key1: 'Scans:', key2: "" + compressedScans.length },
|
|
157
251
|
];
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
worksheet.getRow(i).getCell(2).value = rowData[i - 2].key2;
|
|
172
|
-
}
|
|
173
|
-
// Summary Title
|
|
174
|
-
worksheet.mergeCells('A11', "E11");
|
|
175
|
-
const summaryRow = worksheet.getRow(11);
|
|
176
|
-
summaryRow.height = 27;
|
|
177
|
-
const cellA11 = worksheet.getCell('A11');
|
|
178
|
-
cellA11.value = "Summary";
|
|
179
|
-
cellA11.alignment = { vertical: "middle", horizontal: "left" };
|
|
180
|
-
cellA11.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
|
|
181
|
-
cellA11.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
182
|
-
// Scans info Headers
|
|
183
|
-
worksheet.getRow(12).height = 16; // actual height is
|
|
184
|
-
const cellA12 = worksheet.getCell('A12');
|
|
185
|
-
cellA12.value = "Total issues";
|
|
186
|
-
const cellB12 = worksheet.getCell('B12');
|
|
187
|
-
cellB12.value = "Violations";
|
|
188
|
-
const cellC12 = worksheet.getCell('C12');
|
|
189
|
-
cellC12.value = "Needs review";
|
|
190
|
-
const cellD12 = worksheet.getCell('D12');
|
|
191
|
-
cellD12.value = "Recommendations";
|
|
192
|
-
const cellE12 = worksheet.getCell('E12');
|
|
193
|
-
cellE12.value = "Archived";
|
|
194
|
-
const cellObjects1 = [cellA12, cellB12, cellC12, cellD12, cellE12];
|
|
195
|
-
for (let i = 0; i < cellObjects1.length; i++) {
|
|
196
|
-
cellObjects1[i].alignment = { vertical: "middle", horizontal: "center" };
|
|
197
|
-
if (i == 1 || i == 2 || i == 3 || i === 4) {
|
|
198
|
-
cellObjects1[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
|
|
199
|
-
}
|
|
200
|
-
else {
|
|
201
|
-
cellObjects1[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
|
|
202
|
-
}
|
|
203
|
-
// cellObjects1[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} };
|
|
204
|
-
cellObjects1[i].border = {
|
|
205
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
206
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
207
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
208
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
cellA12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
|
|
212
|
-
cellB12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } };
|
|
213
|
-
cellC12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } };
|
|
214
|
-
cellD12.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } };
|
|
215
|
-
// Scans info Values
|
|
216
|
-
worksheet.getRow(13).height = 27; // actual height is
|
|
217
|
-
const cellA13 = worksheet.getCell('A13');
|
|
218
|
-
cellA13.value = totalIssues;
|
|
219
|
-
const cellB13 = worksheet.getCell('B13');
|
|
220
|
-
cellB13.value = violations;
|
|
221
|
-
const cellC13 = worksheet.getCell('C13');
|
|
222
|
-
cellC13.value = needsReviews;
|
|
223
|
-
const cellD13 = worksheet.getCell('D13');
|
|
224
|
-
cellD13.value = recommendations;
|
|
225
|
-
const cellE13 = worksheet.getCell('E13');
|
|
226
|
-
cellE13.value = archived;
|
|
227
|
-
const cellObjects2 = [cellA13, cellB13, cellC13, cellD13, cellE13];
|
|
228
|
-
for (let i = 0; i < cellObjects2.length; i++) {
|
|
229
|
-
cellObjects2[i].alignment = { vertical: "middle", horizontal: "center" };
|
|
230
|
-
cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
|
|
231
|
-
// cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
|
|
232
|
-
cellObjects2[i].border = {
|
|
233
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
234
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
235
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
236
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
237
|
-
};
|
|
252
|
+
const data = [];
|
|
253
|
+
// Row 1: Title spanning 5 cols
|
|
254
|
+
data.push([
|
|
255
|
+
{ value: "Accessibility Scan Report", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 },
|
|
256
|
+
null, null, null, null
|
|
257
|
+
]);
|
|
258
|
+
// Rows 2–7: metadata key/value pairs
|
|
259
|
+
for (const row of rowData) {
|
|
260
|
+
data.push([
|
|
261
|
+
dataCell(row.key1, { align: "left", height: 12 }),
|
|
262
|
+
{ value: row.key2, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", columnSpan: 4 },
|
|
263
|
+
null, null, null
|
|
264
|
+
]);
|
|
238
265
|
}
|
|
266
|
+
// Row 8: blank spacer
|
|
267
|
+
data.push([null]);
|
|
268
|
+
// Row 9: blank spacer
|
|
269
|
+
data.push([null]);
|
|
270
|
+
// Row 10: blank spacer
|
|
271
|
+
data.push([null]);
|
|
272
|
+
// Row 11: "Summary" title spanning 5 cols
|
|
273
|
+
data.push([
|
|
274
|
+
{ value: "Summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 5 },
|
|
275
|
+
null, null, null, null
|
|
276
|
+
]);
|
|
277
|
+
// Row 12: column headers
|
|
278
|
+
data.push([
|
|
279
|
+
borderedCell("Total issues", { align: "center", alignVertical: "center", backgroundColor: "#000000", textColor: "#FFFFFF", height: 16 }),
|
|
280
|
+
borderedCell("Violations", { align: "center", alignVertical: "center", backgroundColor: "#E4AAAF", textColor: "#000000" }),
|
|
281
|
+
borderedCell("Needs review", { align: "center", alignVertical: "center", backgroundColor: "#F4E08A", textColor: "#000000" }),
|
|
282
|
+
borderedCell("Recommendations", { align: "center", alignVertical: "center", backgroundColor: "#96A9D7", textColor: "#000000" }),
|
|
283
|
+
borderedCell("Archived", { align: "center", alignVertical: "center", backgroundColor: "#FFFFFF", textColor: "#000000" }),
|
|
284
|
+
]);
|
|
285
|
+
// Row 13: values
|
|
286
|
+
data.push([
|
|
287
|
+
borderedCell(totalIssues, { align: "center", alignVertical: "center", height: 27 }),
|
|
288
|
+
borderedCell(violations, { align: "center", alignVertical: "center" }),
|
|
289
|
+
borderedCell(needsReviews, { align: "center", alignVertical: "center" }),
|
|
290
|
+
borderedCell(recommendations, { align: "center", alignVertical: "center" }),
|
|
291
|
+
borderedCell(archived, { align: "center", alignVertical: "center" }),
|
|
292
|
+
]);
|
|
293
|
+
return { data, sheet: "Overview", columns };
|
|
239
294
|
}
|
|
240
|
-
static createScanSummarySheet(config, compressedScans
|
|
241
|
-
const
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
{
|
|
246
|
-
{
|
|
247
|
-
{
|
|
248
|
-
{
|
|
249
|
-
{
|
|
250
|
-
{
|
|
251
|
-
{ col: 'G', width: 17.17 },
|
|
252
|
-
{ col: 'H', width: 17.17 },
|
|
253
|
-
{ col: 'I', width: 17.17 },
|
|
295
|
+
static createScanSummarySheet(config, compressedScans) {
|
|
296
|
+
const columns = [
|
|
297
|
+
{ width: 27.0 },
|
|
298
|
+
{ width: 46.0 },
|
|
299
|
+
{ width: 20.17 },
|
|
300
|
+
{ width: 18.5 },
|
|
301
|
+
{ width: 17.17 },
|
|
302
|
+
{ width: 17.17 },
|
|
303
|
+
{ width: 17.17 },
|
|
304
|
+
{ width: 17.17 },
|
|
305
|
+
{ width: 17.17 },
|
|
254
306
|
];
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
271
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
272
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
273
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
const cellD1 = worksheet.getCell('D1');
|
|
277
|
-
cellD1.value = "Violations";
|
|
278
|
-
const cellE1 = worksheet.getCell('E1');
|
|
279
|
-
cellE1.value = "Needs review";
|
|
280
|
-
const cellF1 = worksheet.getCell('F1');
|
|
281
|
-
cellF1.value = "Recommendations";
|
|
282
|
-
const cellG1 = worksheet.getCell('G1');
|
|
283
|
-
cellG1.value = "Archived";
|
|
284
|
-
const cellH1 = worksheet.getCell('H1');
|
|
285
|
-
cellH1.value = "% elements without violations";
|
|
286
|
-
const cellI1 = worksheet.getCell('I1');
|
|
287
|
-
cellI1.value = "% elements without violations or items to review";
|
|
288
|
-
const cellObjects2 = [cellD1, cellE1, cellF1, cellG1, cellH1, cellI1];
|
|
289
|
-
for (let i = 0; i < cellObjects2.length; i++) {
|
|
290
|
-
cellObjects2[i].alignment = { vertical: "middle", horizontal: "center", wrapText: true };
|
|
291
|
-
if (i == 0 || i == 1 || i == 2 || i == 3) {
|
|
292
|
-
cellObjects2[i].font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
|
|
293
|
-
}
|
|
294
|
-
else {
|
|
295
|
-
cellObjects2[i].font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
|
|
296
|
-
}
|
|
297
|
-
// cellObjects2[i].fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFC65911'} };
|
|
298
|
-
cellObjects2[i].border = {
|
|
299
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
300
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
301
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
302
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
cellD1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFE4AAAF' } };
|
|
306
|
-
cellE1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFF4E08A' } };
|
|
307
|
-
cellF1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF96A9D7' } };
|
|
308
|
-
cellG1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFFFFFFF' } };
|
|
309
|
-
cellH1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
|
|
310
|
-
cellI1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF000000' } };
|
|
307
|
+
const headerStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", height: 39 };
|
|
308
|
+
const countHeaderStyle = { ...headerStyle, align: "center", wrap: true };
|
|
309
|
+
const data = [];
|
|
310
|
+
// Row 1: header row
|
|
311
|
+
data.push([
|
|
312
|
+
{ value: "Page title", ...headerStyle, align: "left" },
|
|
313
|
+
{ value: "Page url", ...headerStyle, align: "left" },
|
|
314
|
+
{ value: "Scan label", ...headerStyle, align: "left" },
|
|
315
|
+
{ value: "Violations", ...countHeaderStyle, backgroundColor: "#E4AAAF", textColor: "#000000" },
|
|
316
|
+
{ value: "Needs review", ...countHeaderStyle, backgroundColor: "#F4E08A", textColor: "#000000" },
|
|
317
|
+
{ value: "Recommendations", ...countHeaderStyle, backgroundColor: "#96A9D7", textColor: "#000000" },
|
|
318
|
+
{ value: "Archived", ...countHeaderStyle, backgroundColor: "#FFFFFF", textColor: "#000000" },
|
|
319
|
+
{ value: "% elements without violations", ...countHeaderStyle },
|
|
320
|
+
{ value: "% elements without violations or items to review", ...countHeaderStyle },
|
|
321
|
+
]);
|
|
311
322
|
for (const compressedScan of compressedScans) {
|
|
312
323
|
let storedScan = ReporterManager.uncompressReport(compressedScan);
|
|
313
324
|
let counts = storedScan.engineReport.summary.counts;
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
storedScan.
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
counts.
|
|
322
|
-
|
|
323
|
-
|
|
325
|
+
const textStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", height: 37, wrap: true };
|
|
326
|
+
const numStyle = { ...textStyle, align: "center", borderColor: "#A6A6A6", borderStyle: "thin" };
|
|
327
|
+
data.push([
|
|
328
|
+
{ value: storedScan.pageTitle, ...textStyle, align: "left" },
|
|
329
|
+
{ value: storedScan.engineReport.summary.URL, ...textStyle, align: "left" },
|
|
330
|
+
{ value: storedScan.label, ...textStyle, align: "left" },
|
|
331
|
+
{ value: counts.violation, ...numStyle },
|
|
332
|
+
{ value: counts.potentialviolation + counts.manual, ...numStyle },
|
|
333
|
+
{ value: counts.recommendation + counts.potentialrecommendation, ...numStyle },
|
|
334
|
+
{ value: counts.ignored, ...numStyle },
|
|
335
|
+
{ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolation) / counts.elements).toFixed(0)) : 0, ...numStyle },
|
|
336
|
+
{ value: counts.elements > 0 ? parseFloat((100 * (counts.elements - counts.elementsViolationReview) / counts.elements).toFixed(0)) : 0, ...numStyle },
|
|
324
337
|
]);
|
|
325
|
-
row.height = 37; // actual height is
|
|
326
|
-
for (let i = 1; i < 4; i++) {
|
|
327
|
-
row.getCell(i).alignment = { vertical: "middle", horizontal: "left", wrapText: true };
|
|
328
|
-
row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 };
|
|
329
|
-
}
|
|
330
|
-
for (let i = 4; i < 10; i++) {
|
|
331
|
-
row.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true };
|
|
332
|
-
row.getCell(i).font = { name: "Calibri", color: { argb: "00000000" }, size: 12 };
|
|
333
|
-
// row.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
|
|
334
|
-
row.getCell(i).border = {
|
|
335
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
336
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
337
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
338
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
row.commit();
|
|
342
338
|
}
|
|
343
|
-
|
|
339
|
+
return { data, sheet: "Scan summary", columns };
|
|
344
340
|
}
|
|
345
|
-
static
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
level1ViolationRow.getCell(1).border = {
|
|
355
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
356
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
357
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
358
|
-
// right: {style:'thin', color: {argb: 'FFA6A6A6'}}
|
|
359
|
-
};
|
|
360
|
-
const cellB6 = level1ViolationRow.getCell(2);
|
|
361
|
-
cellB6.value = levelCount; // total level violations
|
|
362
|
-
cellB6.alignment = { vertical: "middle", horizontal: "right" };
|
|
363
|
-
cellB6.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
|
|
364
|
-
cellB6.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: fillColor } };
|
|
365
|
-
level1ViolationRow.getCell(2).border = {
|
|
366
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
367
|
-
// left: {style:'thin', color: {argb: 'FFA6A6A6'}},
|
|
368
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
369
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
370
|
-
};
|
|
371
|
-
// Level 1 Violation Rows
|
|
372
|
-
// build rows
|
|
373
|
-
let rowArray = [];
|
|
374
|
-
// let row:any =[];
|
|
341
|
+
static buildIssueSummaryLevelRows(fillColor, textColor, title, levelCount, levelrowValues) {
|
|
342
|
+
const rows = [];
|
|
343
|
+
// Level type title row (e.g. "Violations")
|
|
344
|
+
rows.push([
|
|
345
|
+
{ value: ` ${title}`, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 18 },
|
|
346
|
+
{ value: levelCount, backgroundColor: fillColor, textColor, fontFamily: "Calibri", fontSize: 12, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" },
|
|
347
|
+
]);
|
|
348
|
+
// Individual issue message rows, sorted descending by count
|
|
349
|
+
const rowArray = [];
|
|
375
350
|
for (const property in levelrowValues) {
|
|
376
|
-
|
|
377
|
-
];
|
|
378
|
-
rowArray.push(row);
|
|
351
|
+
rowArray.push([" " + property, parseInt(`${levelrowValues[property]}`)]);
|
|
379
352
|
}
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
row.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
|
|
387
|
-
row.getCell(2).alignment = { vertical: "middle", horizontal: "right" };
|
|
388
|
-
row.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
|
|
389
|
-
// row.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
|
|
390
|
-
// row.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor:{argb:'FFf8cbad'} };
|
|
391
|
-
row.getCell(1).border = {
|
|
392
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
393
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
394
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
395
|
-
// right: {style:'thin', color: {argb: 'FFA6A6A6'}}
|
|
396
|
-
};
|
|
397
|
-
row.getCell(2).border = {
|
|
398
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
399
|
-
// left: {style:'thin', color: {argb: 'FFA6A6A6'}},
|
|
400
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
401
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
402
|
-
};
|
|
403
|
-
row.commit();
|
|
353
|
+
rowArray.sort((a, b) => b[1] - a[1]);
|
|
354
|
+
for (const [msg, count] of rowArray) {
|
|
355
|
+
rows.push([
|
|
356
|
+
{ value: msg, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left", height: 14 },
|
|
357
|
+
{ value: count, fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" },
|
|
358
|
+
]);
|
|
404
359
|
}
|
|
360
|
+
return rows;
|
|
405
361
|
}
|
|
406
|
-
static
|
|
407
|
-
|
|
408
|
-
//
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
cellA5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
417
|
-
const cellB5 = level1Row.getCell(2);
|
|
418
|
-
cellB5.value = levelCounts[0]; // total Level 1 issues
|
|
419
|
-
cellB5.alignment = { vertical: "middle", horizontal: "right" };
|
|
420
|
-
cellB5.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
|
|
421
|
-
cellB5.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
422
|
-
ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFE4AAAF", "Violation", levelCounts[1], levelVrowValues);
|
|
423
|
-
ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FFF4E08A", "Needs review", levelCounts[2], levelNRrowValues);
|
|
424
|
-
ACReporterXLSX.buildIssueSummaryLevel(worksheet, "FF96A9D7", "Recommendation", levelCounts[3], levelRrowValues);
|
|
362
|
+
static buildIssueSummaryTKLevelRows(title, levelCounts, levelVrowValues, levelNRrowValues, levelRrowValues, levelArowValues) {
|
|
363
|
+
const rows = [];
|
|
364
|
+
// Level title row (e.g. "Level 1 - the most essential...")
|
|
365
|
+
rows.push([
|
|
366
|
+
{ value: title, backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 },
|
|
367
|
+
{ value: levelCounts[0], backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" },
|
|
368
|
+
]);
|
|
369
|
+
rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#E4AAAF", "#000000", "Violation", levelCounts[1], levelVrowValues));
|
|
370
|
+
rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#F4E08A", "#000000", "Needs review", levelCounts[2], levelNRrowValues));
|
|
371
|
+
rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#96A9D7", "#000000", "Recommendation", levelCounts[3], levelRrowValues));
|
|
425
372
|
if (levelCounts[4] > 0) {
|
|
426
|
-
ACReporterXLSX.
|
|
373
|
+
rows.push(...ACReporterXLSX.buildIssueSummaryLevelRows("#CCCCCC", "#000000", "Archived", levelCounts[4], levelArowValues));
|
|
427
374
|
}
|
|
375
|
+
return rows;
|
|
428
376
|
}
|
|
429
|
-
static createIssueSummarySheet(config, policyInfo, compressedScans
|
|
377
|
+
static createIssueSummarySheet(config, policyInfo, compressedScans) {
|
|
430
378
|
let violations = 0;
|
|
431
379
|
let needsReviews = 0;
|
|
432
380
|
let recommendations = 0;
|
|
@@ -441,8 +389,7 @@ export class ACReporterXLSX {
|
|
|
441
389
|
archive += counts.ignored;
|
|
442
390
|
}
|
|
443
391
|
totalIssues = violations + needsReviews + recommendations;
|
|
444
|
-
|
|
445
|
-
let level1Counts = [0, 0, 0, 0, 0]; // level 1 total issues, violations, needs reviews, recommendations
|
|
392
|
+
let level1Counts = [0, 0, 0, 0, 0];
|
|
446
393
|
let level2Counts = [0, 0, 0, 0, 0];
|
|
447
394
|
let level3Counts = [0, 0, 0, 0, 0];
|
|
448
395
|
let level4Counts = [0, 0, 0, 0, 0];
|
|
@@ -466,10 +413,7 @@ export class ACReporterXLSX {
|
|
|
466
413
|
let scan = ReporterManager.uncompressReport(compressedScan);
|
|
467
414
|
for (const issue of scan.engineReport.results) {
|
|
468
415
|
if (!(issue.ruleId in policyInfo)) {
|
|
469
|
-
policyInfo[issue.ruleId] = {
|
|
470
|
-
tkLevels: [],
|
|
471
|
-
cps: []
|
|
472
|
-
};
|
|
416
|
+
policyInfo[issue.ruleId] = { tkLevels: [], cps: [] };
|
|
473
417
|
}
|
|
474
418
|
let levelCounts, levelV, levelNR, levelR, levelA;
|
|
475
419
|
const issuePolicyInfo = policyInfo[issue.ruleId];
|
|
@@ -523,111 +467,69 @@ export class ACReporterXLSX {
|
|
|
523
467
|
}
|
|
524
468
|
}
|
|
525
469
|
// @ts-ignore
|
|
526
|
-
let level1VrowValues =
|
|
470
|
+
let level1VrowValues = ACReporterXLSX.countDuplicatesInArray(level1V);
|
|
527
471
|
// @ts-ignore
|
|
528
|
-
let level1NRrowValues =
|
|
472
|
+
let level1NRrowValues = ACReporterXLSX.countDuplicatesInArray(level1NR);
|
|
529
473
|
// @ts-ignore
|
|
530
|
-
let level1RrowValues =
|
|
474
|
+
let level1RrowValues = ACReporterXLSX.countDuplicatesInArray(level1R);
|
|
531
475
|
// @ts-ignore
|
|
532
|
-
let level1ArowValues =
|
|
476
|
+
let level1ArowValues = ACReporterXLSX.countDuplicatesInArray(level1A);
|
|
533
477
|
// @ts-ignore
|
|
534
|
-
let level2VrowValues =
|
|
478
|
+
let level2VrowValues = ACReporterXLSX.countDuplicatesInArray(level2V);
|
|
535
479
|
// @ts-ignore
|
|
536
|
-
let level2NRrowValues =
|
|
480
|
+
let level2NRrowValues = ACReporterXLSX.countDuplicatesInArray(level2NR);
|
|
537
481
|
// @ts-ignore
|
|
538
|
-
let level2RrowValues =
|
|
482
|
+
let level2RrowValues = ACReporterXLSX.countDuplicatesInArray(level2R);
|
|
539
483
|
// @ts-ignore
|
|
540
|
-
let level2ArowValues =
|
|
484
|
+
let level2ArowValues = ACReporterXLSX.countDuplicatesInArray(level2A);
|
|
541
485
|
// @ts-ignore
|
|
542
|
-
let level3VrowValues =
|
|
486
|
+
let level3VrowValues = ACReporterXLSX.countDuplicatesInArray(level3V);
|
|
543
487
|
// @ts-ignore
|
|
544
|
-
let level3NRrowValues =
|
|
488
|
+
let level3NRrowValues = ACReporterXLSX.countDuplicatesInArray(level3NR);
|
|
545
489
|
// @ts-ignore
|
|
546
|
-
let level3RrowValues =
|
|
490
|
+
let level3RrowValues = ACReporterXLSX.countDuplicatesInArray(level3R);
|
|
547
491
|
// @ts-ignore
|
|
548
|
-
let level3ArowValues =
|
|
492
|
+
let level3ArowValues = ACReporterXLSX.countDuplicatesInArray(level3A);
|
|
549
493
|
// @ts-ignore
|
|
550
|
-
let level4VrowValues =
|
|
494
|
+
let level4VrowValues = ACReporterXLSX.countDuplicatesInArray(level4V);
|
|
551
495
|
// @ts-ignore
|
|
552
|
-
let level4NRrowValues =
|
|
496
|
+
let level4NRrowValues = ACReporterXLSX.countDuplicatesInArray(level4NR);
|
|
553
497
|
// @ts-ignore
|
|
554
|
-
let level4RrowValues =
|
|
498
|
+
let level4RrowValues = ACReporterXLSX.countDuplicatesInArray(level4R);
|
|
555
499
|
// @ts-ignore
|
|
556
|
-
let level4ArowValues =
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
// 2. for each level sort by V, NR and R
|
|
561
|
-
// 3. for each V, NR, and R in a level get issue dup counts
|
|
562
|
-
// 4. build the rows
|
|
563
|
-
// build Issue summary title
|
|
564
|
-
worksheet.mergeCells('A1', "B1");
|
|
565
|
-
const titleRow = worksheet.getRow(1);
|
|
566
|
-
titleRow.height = 27; // actual is 36
|
|
567
|
-
const cellA1 = worksheet.getCell('A1');
|
|
568
|
-
cellA1.value = "Issue summary";
|
|
569
|
-
cellA1.alignment = { vertical: "middle", horizontal: "left" };
|
|
570
|
-
cellA1.font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
|
|
571
|
-
cellA1.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
572
|
-
const colWidthData = [
|
|
573
|
-
{ col: 'A', width: 155.51 }, // note .84 added to actual width
|
|
574
|
-
{ col: 'B', width: 21.16 },
|
|
500
|
+
let level4ArowValues = ACReporterXLSX.countDuplicatesInArray(level4A);
|
|
501
|
+
const columns = [
|
|
502
|
+
{ width: 155.51 },
|
|
503
|
+
{ width: 21.16 },
|
|
575
504
|
];
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
//
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
// build Number of issues title
|
|
603
|
-
const numberOfIssuesRow = worksheet.getRow(4);
|
|
604
|
-
numberOfIssuesRow.height = 20.25; // actual is 27
|
|
605
|
-
const cellA4 = worksheet.getCell("A4");
|
|
606
|
-
// no value
|
|
607
|
-
cellA4.alignment = { vertical: "middle", horizontal: "left" };
|
|
608
|
-
cellA4.border = {
|
|
609
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
610
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
611
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
612
|
-
right: { style: 'thin', color: { argb: 'FFFFFFFF' } }
|
|
613
|
-
};
|
|
614
|
-
const cellB4 = worksheet.getCell("B4");
|
|
615
|
-
cellB4.value = "Number of issues";
|
|
616
|
-
cellB4.alignment = { vertical: "middle", horizontal: "right" };
|
|
617
|
-
cellB4.font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
|
|
618
|
-
cellB4.border = {
|
|
619
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
620
|
-
left: { style: 'thin', color: { argb: 'FFFFFFFF' } },
|
|
621
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
622
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
623
|
-
};
|
|
624
|
-
ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues);
|
|
625
|
-
ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues);
|
|
626
|
-
ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues);
|
|
627
|
-
ACReporterXLSX.buildIssueSummaryTKLevel(worksheet, "Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues);
|
|
628
|
-
worksheet.commit();
|
|
505
|
+
const data = [];
|
|
506
|
+
// Row 1: "Issue summary" title spanning 2 cols
|
|
507
|
+
data.push([
|
|
508
|
+
{ value: "Issue summary", backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27, columnSpan: 2 },
|
|
509
|
+
null
|
|
510
|
+
]);
|
|
511
|
+
// Row 2: description spanning 2 cols
|
|
512
|
+
data.push([
|
|
513
|
+
{ value: " In the IBM Equal Access Toolkit, issues are divided into three levels (1-3). Tackle the levels in order to address some of the most impactful issues first.", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", alignVertical: "center", align: "left", height: 20, columnSpan: 2 },
|
|
514
|
+
null
|
|
515
|
+
]);
|
|
516
|
+
// Row 3: "Total issues found:" with value
|
|
517
|
+
data.push([
|
|
518
|
+
{ value: "Total issues found:", backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left", height: 27 },
|
|
519
|
+
{ value: totalIssues, backgroundColor: "#000000", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "right" },
|
|
520
|
+
]);
|
|
521
|
+
// Row 4: "Number of issues" label
|
|
522
|
+
data.push([
|
|
523
|
+
{ value: null, borderColor: "#A6A6A6", borderStyle: "thin", height: 20 },
|
|
524
|
+
{ value: "Number of issues", fontFamily: "Calibri", fontSize: 12, textColor: "#000000", borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "right" },
|
|
525
|
+
]);
|
|
526
|
+
data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 1 - the most essential issues to address", level1Counts, level1VrowValues, level1NRrowValues, level1RrowValues, level1ArowValues));
|
|
527
|
+
data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 2 - the next most important issues", level2Counts, level2VrowValues, level2NRrowValues, level2RrowValues, level2ArowValues));
|
|
528
|
+
data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 3 - necessary to meet requirements", level3Counts, level3VrowValues, level3NRrowValues, level3RrowValues, level3ArowValues));
|
|
529
|
+
data.push(...ACReporterXLSX.buildIssueSummaryTKLevelRows("Level 4 - further recommended improvements to accessibility", level4Counts, level4VrowValues, level4NRrowValues, level4RrowValues, level4ArowValues));
|
|
530
|
+
return { data, sheet: "Issue summary", columns };
|
|
629
531
|
}
|
|
630
|
-
static createIssuesSheet(config, policyInfo, compressedScans
|
|
532
|
+
static createIssuesSheet(config, policyInfo, compressedScans) {
|
|
631
533
|
const valueMap = {
|
|
632
534
|
"VIOLATION": {
|
|
633
535
|
"POTENTIAL": "Needs review",
|
|
@@ -648,17 +550,48 @@ export class ACReporterXLSX {
|
|
|
648
550
|
"MANUAL": "Recommendation"
|
|
649
551
|
}
|
|
650
552
|
};
|
|
651
|
-
const
|
|
652
|
-
|
|
653
|
-
|
|
553
|
+
const columns = [
|
|
554
|
+
{ width: 18.0 },
|
|
555
|
+
{ width: 20.5 },
|
|
556
|
+
{ width: 21.0 },
|
|
557
|
+
{ width: 18.5 },
|
|
558
|
+
{ width: 17.0 },
|
|
559
|
+
{ width: 17.17 },
|
|
560
|
+
{ width: 17.17 },
|
|
561
|
+
{ width: 17.17 },
|
|
562
|
+
{ width: 17.17 },
|
|
563
|
+
{ width: 17.17 },
|
|
564
|
+
{ width: 14.00 },
|
|
565
|
+
{ width: 17.17 },
|
|
566
|
+
{ width: 43.00 },
|
|
567
|
+
{ width: 17.17 },
|
|
568
|
+
];
|
|
569
|
+
// Header and data row colors are intentionally omitted — the Excel table
|
|
570
|
+
// (TableStyleMedium2 + showRowStripes) applied by injectTableIntoFile() provides all coloring.
|
|
571
|
+
const hStyle = { fontFamily: "Calibri", fontSize: 12, align: "center", alignVertical: "center", wrap: true, height: 24 };
|
|
572
|
+
const data = [];
|
|
573
|
+
// Header row
|
|
574
|
+
data.push([
|
|
575
|
+
{ value: "Page title", ...hStyle },
|
|
576
|
+
{ value: "Page URL", ...hStyle },
|
|
577
|
+
{ value: "Scan label", ...hStyle },
|
|
578
|
+
{ value: "Issue ID", ...hStyle },
|
|
579
|
+
{ value: "Issue type", ...hStyle },
|
|
580
|
+
{ value: "Toolkit level", ...hStyle },
|
|
581
|
+
{ value: "Checkpoint", ...hStyle },
|
|
582
|
+
{ value: "WCAG level", ...hStyle },
|
|
583
|
+
{ value: "Rule", ...hStyle },
|
|
584
|
+
{ value: "Issue", ...hStyle },
|
|
585
|
+
{ value: "Element", ...hStyle },
|
|
586
|
+
{ value: "Code", ...hStyle },
|
|
587
|
+
{ value: "Xpath", ...hStyle },
|
|
588
|
+
{ value: "Help", ...hStyle },
|
|
589
|
+
]);
|
|
654
590
|
for (const compressedScan of compressedScans) {
|
|
655
591
|
let storedScan = ReporterManager.uncompressReport(compressedScan);
|
|
656
592
|
for (const item of storedScan.engineReport.results) {
|
|
657
593
|
if (!(item.ruleId in policyInfo)) {
|
|
658
|
-
policyInfo[item.ruleId] = {
|
|
659
|
-
tkLevels: [],
|
|
660
|
-
cps: []
|
|
661
|
-
};
|
|
594
|
+
policyInfo[item.ruleId] = { tkLevels: [], cps: [] };
|
|
662
595
|
}
|
|
663
596
|
let polInfo = policyInfo[item.ruleId];
|
|
664
597
|
let cps = polInfo.cps.filter(cp => {
|
|
@@ -669,195 +602,37 @@ export class ACReporterXLSX {
|
|
|
669
602
|
wcagLevels.sort();
|
|
670
603
|
let cpStrs = dropDupes(cps.map(cp => `${cp.num} ${cp.name}`));
|
|
671
604
|
cpStrs.sort();
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
storedScan.
|
|
675
|
-
storedScan.
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
item.
|
|
683
|
-
|
|
684
|
-
item.snippet
|
|
685
|
-
item.
|
|
686
|
-
item.
|
|
687
|
-
item.
|
|
688
|
-
|
|
689
|
-
];
|
|
690
|
-
// let row = [myStoredData[i][0], myStoredData[i][1], storedScans[j].label,
|
|
691
|
-
// myStoredData[i][3], myStoredData[i][4], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][5],
|
|
692
|
-
// myStoredData[i][6], Number.isNaN(myStoredData[i][5]) ? "n/a" : myStoredData[i][7], myStoredData[i][8],
|
|
693
|
-
// myStoredData[i][9], myStoredData[i][10], myStoredData[i][11],
|
|
694
|
-
// myStoredData[i][12], myStoredData[i][13]
|
|
695
|
-
// ];
|
|
696
|
-
rowArray.push(row);
|
|
697
|
-
}
|
|
698
|
-
}
|
|
699
|
-
// column widths
|
|
700
|
-
const colWidthData = [
|
|
701
|
-
{ col: 'A', width: 18.0, alignment: { vertical: "middle", horizontal: "left" } },
|
|
702
|
-
{ col: 'B', width: 20.5, alignment: { vertical: "middle", horizontal: "left" } },
|
|
703
|
-
{ col: 'C', width: 21.0, alignment: { vertical: "middle", horizontal: "center" } },
|
|
704
|
-
{ col: 'D', width: 18.5, alignment: { vertical: "middle", horizontal: "left" } },
|
|
705
|
-
{ col: 'E', width: 17.0, alignment: { vertical: "middle", horizontal: "center" } },
|
|
706
|
-
{ col: 'F', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } },
|
|
707
|
-
{ col: 'G', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
|
|
708
|
-
{ col: 'H', width: 17.17, alignment: { vertical: "middle", horizontal: "center" } },
|
|
709
|
-
{ col: 'I', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
|
|
710
|
-
{ col: 'J', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
|
|
711
|
-
{ col: 'K', width: 14.00, alignment: { vertical: "middle", horizontal: "center" } },
|
|
712
|
-
{ col: 'L', width: 17.17, alignment: { vertical: "middle", horizontal: "left" } },
|
|
713
|
-
{ col: 'M', width: 43.00, alignment: { vertical: "middle", horizontal: "left" } },
|
|
714
|
-
{ col: 'N', width: 17.17, alignment: { vertical: "middle", horizontal: "fill" } },
|
|
715
|
-
];
|
|
716
|
-
for (let i = 0; i < 14; i++) {
|
|
717
|
-
worksheet.getColumn(colWidthData[i].col).width = colWidthData[i].width;
|
|
718
|
-
worksheet.getColumn(colWidthData[i].col).alignment = colWidthData[i].alignment;
|
|
719
|
-
}
|
|
720
|
-
// add table to a sheet
|
|
721
|
-
let headRow = worksheet.addRow([
|
|
722
|
-
"Page title",
|
|
723
|
-
"Page URL",
|
|
724
|
-
"Scan label",
|
|
725
|
-
"Issue ID",
|
|
726
|
-
"Issue type",
|
|
727
|
-
"Toolkit level",
|
|
728
|
-
"Checkpoint",
|
|
729
|
-
"WCAG level",
|
|
730
|
-
"Rule",
|
|
731
|
-
"Issue",
|
|
732
|
-
"Element",
|
|
733
|
-
"Code",
|
|
734
|
-
"Xpath",
|
|
735
|
-
"Help",
|
|
736
|
-
""
|
|
737
|
-
]);
|
|
738
|
-
// set font and alignment for the header cells
|
|
739
|
-
for (let i = 1; i < 15; i++) {
|
|
740
|
-
headRow.getCell(i).alignment = { vertical: "middle", horizontal: "center", wrapText: true };
|
|
741
|
-
headRow.getCell(i).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 12 };
|
|
742
|
-
headRow.getCell(i).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
743
|
-
headRow.getCell(i).border = {
|
|
744
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
745
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
746
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
747
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
748
|
-
};
|
|
749
|
-
}
|
|
750
|
-
// height for header row
|
|
751
|
-
headRow.height = 24;
|
|
752
|
-
headRow.commit();
|
|
753
|
-
for (const rowInfo of rowArray) {
|
|
754
|
-
const row = worksheet.addRow(rowInfo);
|
|
755
|
-
row.height = 14;
|
|
756
|
-
for (let j = 1; j <= 14; j++) {
|
|
757
|
-
row.getCell(j).border = {
|
|
758
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
759
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
760
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
761
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
762
|
-
};
|
|
605
|
+
const dStyle = { fontFamily: "Calibri", fontSize: 12, height: 14 };
|
|
606
|
+
data.push([
|
|
607
|
+
{ value: storedScan.pageTitle, ...dStyle, align: "left", alignVertical: "center" },
|
|
608
|
+
{ value: storedScan.engineReport.summary.URL, ...dStyle, align: "left", alignVertical: "center" },
|
|
609
|
+
{ value: storedScan.label, ...dStyle, align: "center", alignVertical: "center" },
|
|
610
|
+
{ value: ACReporterXLSX.stringHash(item.ruleId + item.path.dom), ...dStyle, align: "left", alignVertical: "center" },
|
|
611
|
+
{ value: `${valueMap[item.value[0]][item.value[1]]}${item.ignored ? ` (Archived)` : ``}`, ...dStyle, align: "center", alignVertical: "center" },
|
|
612
|
+
{ value: polInfo.tkLevels.join(", "), ...dStyle, align: "center", alignVertical: "center" },
|
|
613
|
+
{ value: cpStrs.join("; "), ...dStyle, align: "left", alignVertical: "center" },
|
|
614
|
+
{ value: wcagLevels.join(", "), ...dStyle, align: "center", alignVertical: "center" },
|
|
615
|
+
{ value: item.ruleId, ...dStyle, align: "left", alignVertical: "center" },
|
|
616
|
+
{ value: item.message.substring(0, 32767), ...dStyle, align: "left", alignVertical: "center" },
|
|
617
|
+
{ value: ACReporterXLSX.get_element(item.snippet), ...dStyle, align: "center", alignVertical: "center" },
|
|
618
|
+
{ value: item.snippet.substring(0, 32767), ...dStyle, align: "left", alignVertical: "center" },
|
|
619
|
+
{ value: item.path.dom, ...dStyle, align: "left", alignVertical: "center" },
|
|
620
|
+
{ value: item.help, ...dStyle, align: "left", alignVertical: "center" },
|
|
621
|
+
]);
|
|
763
622
|
}
|
|
764
|
-
row.commit();
|
|
765
623
|
}
|
|
766
|
-
|
|
767
|
-
if (typeof worksheet[key] === "function") {
|
|
768
|
-
console.log(key);
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
// worksheet.addTable({
|
|
772
|
-
// name: 'MyTable',
|
|
773
|
-
// ref: 'A1',
|
|
774
|
-
// headerRow: true,
|
|
775
|
-
// // totalsRow: true,
|
|
776
|
-
// style: {
|
|
777
|
-
// theme: 'TableStyleMedium2',
|
|
778
|
-
// showRowStripes: true,
|
|
779
|
-
// },
|
|
780
|
-
// columns: [
|
|
781
|
-
// { name: 'Page title', filterButton: true },
|
|
782
|
-
// { name: 'Page URL', filterButton: true },
|
|
783
|
-
// { name: 'Scan label', filterButton: true },
|
|
784
|
-
// { name: 'Issue ID', filterButton: true },
|
|
785
|
-
// { name: 'Issue type', filterButton: true },
|
|
786
|
-
// { name: 'Toolkit level', filterButton: true },
|
|
787
|
-
// { name: 'Checkpoint', filterButton: true },
|
|
788
|
-
// { name: 'WCAG level', filterButton: true },
|
|
789
|
-
// { name: 'Rule', filterButton: true },
|
|
790
|
-
// { name: 'Issue', filterButton: true },
|
|
791
|
-
// { name: 'Element', filterButton: true },
|
|
792
|
-
// { name: 'Code', filterButton: true },
|
|
793
|
-
// { name: 'Xpath', filterButton: true },
|
|
794
|
-
// { name: 'Help', filterButton: true },
|
|
795
|
-
// ],
|
|
796
|
-
// rows: rowArray
|
|
797
|
-
// });
|
|
798
|
-
// for (let i = 2; i <= rowArray.length + 1; i++) {
|
|
799
|
-
// worksheet.getRow(i).height = 14;
|
|
800
|
-
// for (let j = 1; j <= 14; j++) {
|
|
801
|
-
// worksheet.getRow(i).getCell(j).border = {
|
|
802
|
-
// top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
803
|
-
// left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
804
|
-
// bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
805
|
-
// right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
806
|
-
// }
|
|
807
|
-
// }
|
|
808
|
-
// worksheet.getRow(i).commit();
|
|
809
|
-
// }
|
|
810
|
-
worksheet.commit();
|
|
624
|
+
return { data, sheet: "Issues", columns, stickyRowsCount: 1, _issueRowCount: data.length };
|
|
811
625
|
}
|
|
812
|
-
static createDefinitionsSheet(
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
const titleRow = worksheet.getRow(1);
|
|
817
|
-
titleRow.height = 36; // actual is 48
|
|
818
|
-
titleRow.getCell(1).value = "Definition of fields";
|
|
819
|
-
titleRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
|
|
820
|
-
titleRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: "20" };
|
|
821
|
-
titleRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
822
|
-
const colWidthData = [
|
|
823
|
-
{ col: 'A', width: '41.51' }, // note .84 added to actual width
|
|
824
|
-
{ col: 'B', width: '119.51' },
|
|
626
|
+
static createDefinitionsSheet() {
|
|
627
|
+
const columns = [
|
|
628
|
+
{ width: 41.51 },
|
|
629
|
+
{ width: 119.51 },
|
|
825
630
|
];
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
const blankRow = worksheet.getRow(2);
|
|
832
|
-
blankRow.height = 12; // actual is 16
|
|
833
|
-
// "Scan summary and Issue summary" title
|
|
834
|
-
worksheet.mergeCells('A3', "B3");
|
|
835
|
-
const summaryRow = worksheet.getRow(3);
|
|
836
|
-
summaryRow.height = 20; // actual is 26.75
|
|
837
|
-
summaryRow.getCell(1).value = "Scan summary and Issue summary";
|
|
838
|
-
summaryRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
|
|
839
|
-
summaryRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
|
|
840
|
-
summaryRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
841
|
-
// row 4 Field / Definition
|
|
842
|
-
const row4 = worksheet.getRow(4);
|
|
843
|
-
row4.height = 16; // actual is
|
|
844
|
-
row4.getCell(1).value = "Field";
|
|
845
|
-
row4.getCell(2).value = "Definition";
|
|
846
|
-
row4.getCell(1).alignment = row4.getCell(2).alignment = { vertical: "middle", horizontal: "left" };
|
|
847
|
-
row4.getCell(1).font = row4.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 };
|
|
848
|
-
row4.getCell(1).fill = row4.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } };
|
|
849
|
-
row4.getCell(1).border = row4.getCell(2).border = {
|
|
850
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
851
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
852
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
853
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
854
|
-
};
|
|
855
|
-
// rows 5-13
|
|
856
|
-
// set row height for rows 5-13
|
|
857
|
-
for (let i = 5; i < 14; i++) {
|
|
858
|
-
worksheet.getRow(i).height = 12; // results in a row height of 16
|
|
859
|
-
}
|
|
860
|
-
let rowData = [
|
|
631
|
+
const titleStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 20, alignVertical: "center", align: "left" };
|
|
632
|
+
const sectionStyle = { backgroundColor: "#403151", textColor: "#FFFFFF", fontFamily: "Calibri", fontSize: 16, alignVertical: "center", align: "left" };
|
|
633
|
+
const subHeaderStyle = { backgroundColor: "#CCC0DA", textColor: "#000000", fontFamily: "Calibri", fontSize: 16, borderColor: "#A6A6A6", borderStyle: "thin", alignVertical: "center", align: "left" };
|
|
634
|
+
const dataStyle = { fontFamily: "Calibri", fontSize: 12, textColor: "#000000", align: "left", height: 12 };
|
|
635
|
+
const summaryRowData = [
|
|
861
636
|
{ key1: 'Page', key2: 'Identifies the page or html file that was scanned.' },
|
|
862
637
|
{ key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' },
|
|
863
638
|
{ key1: 'Violations', key2: 'Accessibility failures that need to be corrected.' },
|
|
@@ -867,43 +642,7 @@ export class ACReporterXLSX {
|
|
|
867
642
|
{ key1: '% elements without violations or items to review', key2: 'Percentage of elements on the page that had no violations found and no items to review.' },
|
|
868
643
|
{ key1: 'Level 1,2,3', key2: 'Priority level defined by the IBM Equal Access Toolkit. See https://www.ibm.com/able/toolkit/plan/overview#pace-of-completion for details.' }
|
|
869
644
|
];
|
|
870
|
-
|
|
871
|
-
worksheet.getRow(i).getCell(1).font = worksheet.getRow(i).getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 12 };
|
|
872
|
-
worksheet.getRow(i).getCell(1).alignment = worksheet.getRow(i).getCell(2).alignment = { horizontal: "left" };
|
|
873
|
-
}
|
|
874
|
-
for (let i = 5; i < rowData.length + 5; i++) {
|
|
875
|
-
worksheet.getRow(i).getCell(1).value = rowData[i - 5].key1;
|
|
876
|
-
worksheet.getRow(i).getCell(2).value = rowData[i - 5].key2;
|
|
877
|
-
}
|
|
878
|
-
// "Scan summary and Issue summary" title
|
|
879
|
-
worksheet.mergeCells('A14', "B14");
|
|
880
|
-
const issuesRow = worksheet.getRow(14);
|
|
881
|
-
issuesRow.height = 20; // actual is 26.75
|
|
882
|
-
issuesRow.getCell(1).value = "Issues";
|
|
883
|
-
issuesRow.getCell(1).alignment = { vertical: "middle", horizontal: "left" };
|
|
884
|
-
issuesRow.getCell(1).font = { name: "Calibri", color: { argb: "FFFFFFFF" }, size: 16 };
|
|
885
|
-
issuesRow.getCell(1).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF403151' } };
|
|
886
|
-
// row 15 Field / Definition
|
|
887
|
-
const row15 = worksheet.getRow(15);
|
|
888
|
-
row15.height = 16; // actual is
|
|
889
|
-
row15.getCell(1).value = "Field";
|
|
890
|
-
row15.getCell(2).value = "Definition";
|
|
891
|
-
row15.getCell(1).alignment = row15.getCell(2).alignment = { vertical: "middle", horizontal: "left" };
|
|
892
|
-
row15.getCell(1).font = row15.getCell(2).font = { name: "Calibri", color: { argb: "FF000000" }, size: 16 };
|
|
893
|
-
row15.getCell(1).fill = row15.getCell(2).fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FFCCC0DA' } };
|
|
894
|
-
row15.getCell(1).border = row15.getCell(2).border = {
|
|
895
|
-
top: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
896
|
-
left: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
897
|
-
bottom: { style: 'thin', color: { argb: 'FFA6A6A6' } },
|
|
898
|
-
right: { style: 'thin', color: { argb: 'FFA6A6A6' } }
|
|
899
|
-
};
|
|
900
|
-
// rows 16-28
|
|
901
|
-
// set row height for rows 16-28
|
|
902
|
-
for (let i = 16; i < 29; i++) {
|
|
903
|
-
worksheet.getRow(i).height = 12; // results in a row height of 16
|
|
904
|
-
}
|
|
905
|
-
rowData = [];
|
|
906
|
-
rowData = [
|
|
645
|
+
const issuesRowData = [
|
|
907
646
|
{ key1: 'Page', key2: 'Identifies the page or html file that was scanned.' },
|
|
908
647
|
{ key1: 'Scan label', key2: 'Label for the scan. Default values can be edited in the Accessibility Checker before saving this report, or programmatically assigned in automated testing.' },
|
|
909
648
|
{ key1: 'Issue ID', key2: 'Identifier for this issue within this page. Rescanning the same page will produce the same issue ID. ' },
|
|
@@ -918,19 +657,54 @@ export class ACReporterXLSX {
|
|
|
918
657
|
{ key1: 'Xpath', key2: 'Xpath of the HTML element where the issue is found.' },
|
|
919
658
|
{ key1: 'Help', key2: 'Link to a more detailed description of the issue and suggested solutions.' },
|
|
920
659
|
];
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
660
|
+
const data = [];
|
|
661
|
+
// Row 1: "Definition of fields" title spanning 2 cols
|
|
662
|
+
data.push([
|
|
663
|
+
{ value: "Definition of fields", ...titleStyle, height: 36, columnSpan: 2 },
|
|
664
|
+
null
|
|
665
|
+
]);
|
|
666
|
+
// Row 2: blank
|
|
667
|
+
data.push([{ value: null, height: 12, columnSpan: 2 }, null]);
|
|
668
|
+
// Row 3: "Scan summary and Issue summary" section header
|
|
669
|
+
data.push([
|
|
670
|
+
{ value: "Scan summary and Issue summary", ...sectionStyle, height: 20, columnSpan: 2 },
|
|
671
|
+
null
|
|
672
|
+
]);
|
|
673
|
+
// Row 4: "Field / Definition" subheader
|
|
674
|
+
data.push([
|
|
675
|
+
{ value: "Field", ...subHeaderStyle, height: 16 },
|
|
676
|
+
{ value: "Definition", ...subHeaderStyle },
|
|
677
|
+
]);
|
|
678
|
+
// Rows 5–12: scan summary definitions
|
|
679
|
+
for (const row of summaryRowData) {
|
|
680
|
+
data.push([
|
|
681
|
+
{ value: row.key1, ...dataStyle },
|
|
682
|
+
{ value: row.key2, ...dataStyle },
|
|
683
|
+
]);
|
|
924
684
|
}
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
685
|
+
// Row 13: blank (separator between sections) — kept simple
|
|
686
|
+
data.push([{ value: null, height: 12, columnSpan: 2 }, null]);
|
|
687
|
+
// Row 14: "Issues" section header
|
|
688
|
+
data.push([
|
|
689
|
+
{ value: "Issues", ...sectionStyle, height: 20, columnSpan: 2 },
|
|
690
|
+
null
|
|
691
|
+
]);
|
|
692
|
+
// Row 15: "Field / Definition" subheader
|
|
693
|
+
data.push([
|
|
694
|
+
{ value: "Field", ...subHeaderStyle, height: 16 },
|
|
695
|
+
{ value: "Definition", ...subHeaderStyle },
|
|
696
|
+
]);
|
|
697
|
+
// Rows 16–28: issues definitions
|
|
698
|
+
for (const row of issuesRowData) {
|
|
699
|
+
data.push([
|
|
700
|
+
{ value: row.key1, ...dataStyle },
|
|
701
|
+
{ value: row.key2, ...dataStyle },
|
|
702
|
+
]);
|
|
928
703
|
}
|
|
929
|
-
|
|
704
|
+
return { data, sheet: "Definition of fields", columns };
|
|
930
705
|
}
|
|
931
706
|
static countDuplicatesInArray(array) {
|
|
932
707
|
let count = {};
|
|
933
|
-
// let result = [];
|
|
934
708
|
array.forEach(item => {
|
|
935
709
|
if (count[item]) {
|
|
936
710
|
//@ts-ignore
|
|
@@ -964,9 +738,6 @@ export class ACReporterXLSX {
|
|
|
964
738
|
while (i) {
|
|
965
739
|
hash = (hash * 33) ^ str.charCodeAt(--i);
|
|
966
740
|
}
|
|
967
|
-
/* JavaScript does bitwise operations (like XOR, above) on 32-bit signed
|
|
968
|
-
* integers. Since we want the results to be always positive, convert the
|
|
969
|
-
* signed int to an unsigned by doing an unsigned bitshift. */
|
|
970
741
|
return hash >>> 0;
|
|
971
742
|
}
|
|
972
743
|
}
|