@govtechsg/oobee 0.10.20
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/.dockerignore +22 -0
- package/.github/pull_request_template.md +11 -0
- package/.github/workflows/docker-test.yml +54 -0
- package/.github/workflows/image.yml +107 -0
- package/.github/workflows/publish.yml +18 -0
- package/.idea/modules.xml +8 -0
- package/.idea/purple-a11y.iml +9 -0
- package/.idea/vcs.xml +6 -0
- package/.prettierrc.json +12 -0
- package/.vscode/extensions.json +5 -0
- package/.vscode/settings.json +10 -0
- package/CODE_OF_CONDUCT.md +128 -0
- package/DETAILS.md +163 -0
- package/Dockerfile +60 -0
- package/INSTALLATION.md +146 -0
- package/INTEGRATION.md +785 -0
- package/LICENSE +22 -0
- package/README.md +587 -0
- package/SECURITY.md +5 -0
- package/__mocks__/mock-report.html +1431 -0
- package/__mocks__/mockFunctions.ts +32 -0
- package/__mocks__/mockIssues.ts +64 -0
- package/__mocks__/mock_all_issues/000000001.json +64 -0
- package/__mocks__/mock_all_issues/000000002.json +53 -0
- package/__mocks__/mock_all_issues/fake-file.txt +0 -0
- package/__tests__/logs.test.ts +25 -0
- package/__tests__/mergeAxeResults.test.ts +278 -0
- package/__tests__/utils.test.ts +118 -0
- package/a11y-scan-results.zip +0 -0
- package/eslint.config.js +53 -0
- package/exclusions.txt +2 -0
- package/gitlab-pipeline-template.yml +54 -0
- package/jest.config.js +1 -0
- package/package.json +96 -0
- package/scripts/copyFiles.js +44 -0
- package/scripts/install_oobee_dependencies.cmd +13 -0
- package/scripts/install_oobee_dependencies.command +101 -0
- package/scripts/install_oobee_dependencies.ps1 +110 -0
- package/scripts/oobee_shell.cmd +13 -0
- package/scripts/oobee_shell.command +11 -0
- package/scripts/oobee_shell.sh +55 -0
- package/scripts/oobee_shell_ps.ps1 +54 -0
- package/src/cli.ts +401 -0
- package/src/combine.ts +240 -0
- package/src/constants/__tests__/common.test.ts +44 -0
- package/src/constants/cliFunctions.ts +305 -0
- package/src/constants/common.ts +1840 -0
- package/src/constants/constants.ts +443 -0
- package/src/constants/errorMeta.json +319 -0
- package/src/constants/itemTypeDescription.ts +11 -0
- package/src/constants/oobeeAi.ts +141 -0
- package/src/constants/questions.ts +181 -0
- package/src/constants/sampleData.ts +187 -0
- package/src/crawlers/__tests__/commonCrawlerFunc.test.ts +51 -0
- package/src/crawlers/commonCrawlerFunc.ts +656 -0
- package/src/crawlers/crawlDomain.ts +877 -0
- package/src/crawlers/crawlIntelligentSitemap.ts +156 -0
- package/src/crawlers/crawlLocalFile.ts +193 -0
- package/src/crawlers/crawlSitemap.ts +356 -0
- package/src/crawlers/custom/extractAndGradeText.ts +57 -0
- package/src/crawlers/custom/flagUnlabelledClickableElements.ts +964 -0
- package/src/crawlers/custom/utils.ts +486 -0
- package/src/crawlers/customAxeFunctions.ts +82 -0
- package/src/crawlers/pdfScanFunc.ts +468 -0
- package/src/crawlers/runCustom.ts +117 -0
- package/src/index.ts +173 -0
- package/src/logs.ts +66 -0
- package/src/mergeAxeResults.ts +964 -0
- package/src/npmIndex.ts +284 -0
- package/src/screenshotFunc/htmlScreenshotFunc.ts +411 -0
- package/src/screenshotFunc/pdfScreenshotFunc.ts +762 -0
- package/src/static/ejs/partials/components/categorySelector.ejs +4 -0
- package/src/static/ejs/partials/components/categorySelectorDropdown.ejs +57 -0
- package/src/static/ejs/partials/components/pagesScannedModal.ejs +70 -0
- package/src/static/ejs/partials/components/reportSearch.ejs +47 -0
- package/src/static/ejs/partials/components/ruleOffcanvas.ejs +105 -0
- package/src/static/ejs/partials/components/scanAbout.ejs +263 -0
- package/src/static/ejs/partials/components/screenshotLightbox.ejs +13 -0
- package/src/static/ejs/partials/components/summaryScanAbout.ejs +141 -0
- package/src/static/ejs/partials/components/summaryScanResults.ejs +16 -0
- package/src/static/ejs/partials/components/summaryTable.ejs +20 -0
- package/src/static/ejs/partials/components/summaryWcagCompliance.ejs +94 -0
- package/src/static/ejs/partials/components/topFive.ejs +6 -0
- package/src/static/ejs/partials/components/wcagCompliance.ejs +70 -0
- package/src/static/ejs/partials/footer.ejs +21 -0
- package/src/static/ejs/partials/header.ejs +230 -0
- package/src/static/ejs/partials/main.ejs +40 -0
- package/src/static/ejs/partials/scripts/bootstrap.ejs +8 -0
- package/src/static/ejs/partials/scripts/categorySelectorDropdownScript.ejs +190 -0
- package/src/static/ejs/partials/scripts/categorySummary.ejs +141 -0
- package/src/static/ejs/partials/scripts/highlightjs.ejs +335 -0
- package/src/static/ejs/partials/scripts/popper.ejs +7 -0
- package/src/static/ejs/partials/scripts/reportSearch.ejs +248 -0
- package/src/static/ejs/partials/scripts/ruleOffcanvas.ejs +801 -0
- package/src/static/ejs/partials/scripts/screenshotLightbox.ejs +71 -0
- package/src/static/ejs/partials/scripts/summaryScanResults.ejs +14 -0
- package/src/static/ejs/partials/scripts/summaryTable.ejs +78 -0
- package/src/static/ejs/partials/scripts/utils.ejs +441 -0
- package/src/static/ejs/partials/styles/bootstrap.ejs +12375 -0
- package/src/static/ejs/partials/styles/highlightjs.ejs +54 -0
- package/src/static/ejs/partials/styles/styles.ejs +1843 -0
- package/src/static/ejs/partials/styles/summaryBootstrap.ejs +12458 -0
- package/src/static/ejs/partials/summaryHeader.ejs +70 -0
- package/src/static/ejs/partials/summaryMain.ejs +75 -0
- package/src/static/ejs/report.ejs +420 -0
- package/src/static/ejs/summary.ejs +47 -0
- package/src/static/mustache/.prettierrc +4 -0
- package/src/static/mustache/Attention Deficit.mustache +11 -0
- package/src/static/mustache/Blind.mustache +11 -0
- package/src/static/mustache/Cognitive.mustache +7 -0
- package/src/static/mustache/Colorblindness.mustache +20 -0
- package/src/static/mustache/Deaf.mustache +12 -0
- package/src/static/mustache/Deafblind.mustache +7 -0
- package/src/static/mustache/Dyslexia.mustache +14 -0
- package/src/static/mustache/Low Vision.mustache +7 -0
- package/src/static/mustache/Mobility.mustache +15 -0
- package/src/static/mustache/Sighted Keyboard Users.mustache +42 -0
- package/src/static/mustache/report.mustache +1709 -0
- package/src/types/print-message.d.ts +28 -0
- package/src/types/types.ts +46 -0
- package/src/types/xpath-to-css.d.ts +3 -0
- package/src/utils.ts +332 -0
- package/tsconfig.json +15 -0
@@ -0,0 +1,70 @@
|
|
1
|
+
<header aria-label="Report header" id="header">
|
2
|
+
<div class="z-2 flex-row justify-content-between px-3 py-4">
|
3
|
+
<div class="d-flex align-items-center">
|
4
|
+
<svg
|
5
|
+
aria-hidden="true"
|
6
|
+
width="48"
|
7
|
+
height="48"
|
8
|
+
viewBox="0 0 48 48"
|
9
|
+
fill="none"
|
10
|
+
xmlns="http://www.w3.org/2000/svg"
|
11
|
+
>
|
12
|
+
<circle cx="24" cy="24" r="24" fill="#9021a6" />
|
13
|
+
<path
|
14
|
+
d="M16.2528 24.9725V23.832C16.2528 21.5526 14.4057 19.7056 12.1264 19.7056C9.84708 19.7056 8 21.5526 8 23.832V27.0721C8 29.2906 9.74991 31.0986 11.9448 31.1939V29.2806C11.9448 26.905 13.8772 24.9725 16.2528 24.9725Z"
|
15
|
+
fill="white"
|
16
|
+
/>
|
17
|
+
<path
|
18
|
+
d="M12.308 29.28V31.1979H16.2528V25.3352C14.0779 25.3352 12.308 27.1051 12.308 29.28Z"
|
19
|
+
fill="white"
|
20
|
+
/>
|
21
|
+
<path d="M22.8201 25.3289H18.6937V31.1997H22.8201V25.3289Z" fill="white" />
|
22
|
+
<path
|
23
|
+
d="M22.8201 17.6016C20.5408 17.6016 18.6937 19.4486 18.6937 21.728V24.9672H22.8201V17.6016Z"
|
24
|
+
fill="white"
|
25
|
+
/>
|
26
|
+
<path
|
27
|
+
d="M29.3876 17.6016C27.1082 17.6016 25.2612 19.4486 25.2612 21.728V24.9672H29.3876V17.6016Z"
|
28
|
+
fill="white"
|
29
|
+
/>
|
30
|
+
<path d="M29.3876 25.3289H25.2612V31.1997H29.3876V25.3289Z" fill="white" />
|
31
|
+
<path
|
32
|
+
d="M36.3182 31.199C38.5976 31.199 40.4446 29.3519 40.4446 27.0726V25.3281H36.3182V31.199Z"
|
33
|
+
fill="white"
|
34
|
+
/>
|
35
|
+
<path
|
36
|
+
d="M40.4446 19.7056C38.1653 19.7056 36.3182 21.5526 36.3182 23.832V24.9644H40.4446V19.7056Z"
|
37
|
+
fill="white"
|
38
|
+
/>
|
39
|
+
<path
|
40
|
+
d="M35.955 23.832C35.955 21.5526 34.1079 19.7056 31.8286 19.7056V22.844C31.8286 23.6195 32.0429 24.3441 32.4143 24.9644H35.955V23.832Z"
|
41
|
+
fill="white"
|
42
|
+
/>
|
43
|
+
<path
|
44
|
+
d="M35.955 26.9709V25.3281H32.6595C33.4123 26.3261 34.6083 26.9709 35.955 26.9709Z"
|
45
|
+
fill="white"
|
46
|
+
/>
|
47
|
+
</svg>
|
48
|
+
|
49
|
+
<h1 class="d-inline mb-0 ms-3">Oobee Scan Summary</h1>
|
50
|
+
</div>
|
51
|
+
<%#
|
52
|
+
<div class="toggleWrapper">
|
53
|
+
<input tabindex="0" type="checkbox" class="dm" id="dm" />
|
54
|
+
<label for="dm" class="toggle">
|
55
|
+
<span class="toggle__handler">
|
56
|
+
<span class="crater crater--1"></span>
|
57
|
+
<span class="crater crater--2"></span>
|
58
|
+
<span class="crater crater--3"></span>
|
59
|
+
</span>
|
60
|
+
<span class="star star--1"></span>
|
61
|
+
<span class="star star--2"></span>
|
62
|
+
<span class="star star--3"></span>
|
63
|
+
<span class="star star--4"></span>
|
64
|
+
<span class="star star--5"></span>
|
65
|
+
<span class="star star--6"></span>
|
66
|
+
</label>
|
67
|
+
</div>
|
68
|
+
%>
|
69
|
+
</div>
|
70
|
+
</header>
|
@@ -0,0 +1,75 @@
|
|
1
|
+
<div class="flex-grow-1 align-items-stretch">
|
2
|
+
<main aria-label="Report main content" class="d-flex flex-column flex-grow-1">
|
3
|
+
<div class="row m-0 py-4 px-3 d-flex" style="flex-wrap: nowrap">
|
4
|
+
<div id="aboutScanDiv" class="pe-md-2 d-flex" style="flex: 1; flex-basis: 300px">
|
5
|
+
<div
|
6
|
+
id="scanabout-compliance-card"
|
7
|
+
class="card h-100"
|
8
|
+
style="width: -webkit-fill-available"
|
9
|
+
>
|
10
|
+
<div class="card-body"><%- include("components/summaryScanAbout") %></div>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
<div id="scanResultsDiv" class="ps-md-2" style="flex: 2; margin-left: 10px">
|
14
|
+
<div id="summary-scan-results-card" class="card h-100">
|
15
|
+
<div class="card-body">
|
16
|
+
<h2>Scan results</h2>
|
17
|
+
<div class="d-flex justify-content-between align-items-center">
|
18
|
+
<span class="fw-bold"> WCAG (A & AA) Passes </span>
|
19
|
+
<span aria-label="Pass percentage" class="ms-2"><%= wcagPassPercentage %>% of automated checks</span>
|
20
|
+
</div>
|
21
|
+
<div class="wcag-compliance-passes-bar mb-5 d-flex">
|
22
|
+
<svg
|
23
|
+
width="500"
|
24
|
+
role="none"
|
25
|
+
height="6"
|
26
|
+
fill="none"
|
27
|
+
xmlns="http://www.w3.org/2000/svg"
|
28
|
+
style="display: flex; width: 100%; position: absolute"
|
29
|
+
>
|
30
|
+
<rect
|
31
|
+
width="100%"
|
32
|
+
height="10"
|
33
|
+
rx="3"
|
34
|
+
fill="#E7ECEE"
|
35
|
+
style="justify-content: left"
|
36
|
+
></rect>
|
37
|
+
<rect
|
38
|
+
width="<%= wcagPassPercentage %>%"
|
39
|
+
height="6"
|
40
|
+
rx="3"
|
41
|
+
fill="#9021a6"
|
42
|
+
style=""
|
43
|
+
></rect>
|
44
|
+
</svg>
|
45
|
+
</div>
|
46
|
+
<ul class="unbulleted-list">
|
47
|
+
<% Object.keys(items).forEach((category) => { %> <%-
|
48
|
+
include("components/summaryScanResults", { category: category }) %> <% }) %>
|
49
|
+
</ul>
|
50
|
+
</div>
|
51
|
+
</div>
|
52
|
+
</div>
|
53
|
+
</div>
|
54
|
+
<div class="mx-3">
|
55
|
+
<h2 class="mb-2">Summary of issues:</h2>
|
56
|
+
<p>
|
57
|
+
Only a subset of
|
58
|
+
<a
|
59
|
+
href="https://www.w3.org/WAI/WCAG21/quickref/?currentsidebar=%23col_customize&versions=2.1&levels=aaa"
|
60
|
+
target="_blank"
|
61
|
+
>WCAG 2.1</a
|
62
|
+
>
|
63
|
+
(Conformance Level A & AA) Success Criteria can be automatically checked so
|
64
|
+
<a
|
65
|
+
aria-label="Manual testing guide"
|
66
|
+
href="http://go.gov.sg/oobee-manual-testing"
|
67
|
+
target="_blank"
|
68
|
+
>manual testing</a
|
69
|
+
>
|
70
|
+
is still required. For more details, please refer to the HTML report.
|
71
|
+
</p>
|
72
|
+
</div>
|
73
|
+
<%- include("components/summaryTable") %>
|
74
|
+
</main>
|
75
|
+
</div>
|
@@ -0,0 +1,420 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="en" id="accessibility-site-report">
|
3
|
+
<head lang="en">
|
4
|
+
<meta charset="UTF-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
6
|
+
<title>Accessibility Site Report</title>
|
7
|
+
<!-- [TESTCODE] Font Awesome CDN -->
|
8
|
+
<link
|
9
|
+
rel="stylesheet"
|
10
|
+
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css"
|
11
|
+
integrity="sha512-..."
|
12
|
+
crossorigin="anonymous"
|
13
|
+
/>
|
14
|
+
<link
|
15
|
+
rel="icon"
|
16
|
+
type="image/svg+xml"
|
17
|
+
href="data:image/svg+xml,%3Csvg width='48' height='48' viewBox='0 0 48 48' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M23.5 6C11.7707 6 10 11.1369 10 19.23V28.77C10 36.8631 11.7707 42 23.5 42C35.2293 42 37 36.8631 37 28.77V19.23C37 11.1369 35.2293 6 23.5 6ZM25.4903 14.5985V35.0562H21.5097V12.9438H27.8925L25.4903 14.5985Z' fill='%239021A6'/%3E%3C/svg%3E
|
18
|
+
"
|
19
|
+
/>
|
20
|
+
<%- include('partials/styles/bootstrap') %> <%- include('partials/styles/highlightjs') %> <%-
|
21
|
+
include('partials/styles/styles') %>
|
22
|
+
</head>
|
23
|
+
|
24
|
+
<body class="d-flex flex-column">
|
25
|
+
<%- include('partials/header') %> <%- include('partials/main') %> <%-
|
26
|
+
include('partials/scripts/popper') %> <%- include('partials/scripts/bootstrap') %> <%-
|
27
|
+
include('partials/scripts/highlightjs') %> <%- include('partials/scripts/utils') %> <%-
|
28
|
+
include('partials/scripts/categorySelectorDropdownScript') %> <%-
|
29
|
+
include('partials/scripts/categorySummary') %> <%- include('partials/scripts/ruleOffcanvas') %>
|
30
|
+
<%- include('partials/scripts/screenshotLightbox')%>
|
31
|
+
<!-- search feat changes -->
|
32
|
+
<%- include('partials/scripts/reportSearch') %>
|
33
|
+
<script>
|
34
|
+
function initTooltips() {
|
35
|
+
const tooltipTriggerList = [].slice.call(
|
36
|
+
document.querySelectorAll('[data-bs-toggle="tooltip"]'),
|
37
|
+
);
|
38
|
+
tooltipTriggerList.map(tooltipTriggerEl => {
|
39
|
+
const tooltip = new bootstrap.Tooltip(tooltipTriggerEl);
|
40
|
+
tooltipTriggerEl.addEventListener('mouseleave', () => tooltip.hide());
|
41
|
+
return tooltip;
|
42
|
+
});
|
43
|
+
}
|
44
|
+
|
45
|
+
// Scan DATA FUNCTION TO REPLACE NA
|
46
|
+
const scanDataWCAGCompliance = () => {
|
47
|
+
const passPecentage = document.getElementById('passPercentage');
|
48
|
+
passPecentage.innerHTML = scanData.wcagPassPercentage + '% of automated checks';
|
49
|
+
const wcagBarProgess = document.getElementById('wcag-compliance-passes-bar-progress');
|
50
|
+
wcagBarProgess.style.width = `${scanData.wcagPassPercentage}%`; // Set this to your desired width
|
51
|
+
|
52
|
+
const wcagLinksList = document.getElementById('wcagLinksList');
|
53
|
+
|
54
|
+
Object.entries(scanData.wcagLinks).forEach(([key, value]) => {
|
55
|
+
const listItem = document.createElement('li');
|
56
|
+
const link = document.createElement('a');
|
57
|
+
link.href = value;
|
58
|
+
link.target = '_blank';
|
59
|
+
link.textContent = key;
|
60
|
+
listItem.appendChild(link);
|
61
|
+
wcagLinksList.appendChild(listItem);
|
62
|
+
});
|
63
|
+
};
|
64
|
+
|
65
|
+
const scanDataTop5Card = () => {
|
66
|
+
const topIssuesList = document.getElementById('top-issues-list');
|
67
|
+
|
68
|
+
scanData.topFiveMostIssues.forEach(page => {
|
69
|
+
if (page.totalIssues !== 0) {
|
70
|
+
const listItem = document.createElement('li');
|
71
|
+
listItem.className = 'd-flex justify-content-between';
|
72
|
+
|
73
|
+
const link = document.createElement('a');
|
74
|
+
link.href = page.url;
|
75
|
+
link.target = '_blank';
|
76
|
+
link.textContent = page.pageTitle.length > 0 ? page.pageTitle : page.url;
|
77
|
+
|
78
|
+
const issuesSpan = document.createElement('span');
|
79
|
+
issuesSpan.setAttribute('aria-label', `${page.totalIssues} issues`);
|
80
|
+
issuesSpan.className = 'fw-bold ms-2';
|
81
|
+
issuesSpan.ariaLabel = page.totalIssues + 'issues';
|
82
|
+
issuesSpan.textContent = page.totalIssues;
|
83
|
+
|
84
|
+
listItem.appendChild(link);
|
85
|
+
listItem.appendChild(issuesSpan);
|
86
|
+
topIssuesList.appendChild(listItem);
|
87
|
+
}
|
88
|
+
});
|
89
|
+
};
|
90
|
+
|
91
|
+
const scanDataCategorySelector = () => {
|
92
|
+
const formattedCategoryTitles = {
|
93
|
+
mustFix: 'Must Fix',
|
94
|
+
goodToFix: 'Good to Fix',
|
95
|
+
needsReview: 'Needs Review',
|
96
|
+
passed: 'Passed',
|
97
|
+
};
|
98
|
+
|
99
|
+
const scategoryList = document.getElementById('categorySelector');
|
100
|
+
|
101
|
+
Object.keys(scanItems).forEach(category => {
|
102
|
+
if (category !== 'passed') {
|
103
|
+
const categoryData = scanItems[category];
|
104
|
+
const listItem = document.createElement('div');
|
105
|
+
listItem.className = 'col-md-4 px-2';
|
106
|
+
|
107
|
+
const button = document.createElement('button');
|
108
|
+
button.setAttribute('aria-labelledby', `${category}Title ${category}ItemsInformation`);
|
109
|
+
button.setAttribute('aria-describedby', `${category}AriaDescription`);
|
110
|
+
button.id = `${category}Selector`;
|
111
|
+
button.className = `h-100 category-selector ${category}`;
|
112
|
+
button.addEventListener('click', event => changeSelectedCategory(event, category));
|
113
|
+
button.addEventListener('focus', () =>
|
114
|
+
document
|
115
|
+
.getElementById(`${category}Description`)
|
116
|
+
.dispatchEvent(new MouseEvent('mouseover')),
|
117
|
+
);
|
118
|
+
button.addEventListener('blur', () =>
|
119
|
+
document
|
120
|
+
.getElementById(`${category}Description`)
|
121
|
+
.dispatchEvent(new MouseEvent('mouseout')),
|
122
|
+
);
|
123
|
+
button.addEventListener('mousedown', event => event.preventDefault());
|
124
|
+
|
125
|
+
const divFlex = document.createElement('div');
|
126
|
+
divFlex.className = 'd-flex align-items-center mb-3';
|
127
|
+
|
128
|
+
const spanTitle = document.createElement('span');
|
129
|
+
spanTitle.id = `${category}Title`;
|
130
|
+
spanTitle.className = 'd-flex align-items-center category-name fw-bold d-inline mb-0';
|
131
|
+
spanTitle.textContent = formattedCategoryTitles[category];
|
132
|
+
|
133
|
+
const svgIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
134
|
+
svgIcon.setAttribute('tabindex', '-1');
|
135
|
+
svgIcon.id = `${category}Description`;
|
136
|
+
svgIcon.setAttribute('class', 'ms-2');
|
137
|
+
svgIcon.setAttribute('data-bs-toggle', 'tooltip');
|
138
|
+
svgIcon.setAttribute('data-bs-placement', 'top');
|
139
|
+
svgIcon.setAttribute('title', categoryData.description);
|
140
|
+
svgIcon.setAttribute('width', '14');
|
141
|
+
svgIcon.setAttribute('height', '14');
|
142
|
+
svgIcon.setAttribute('viewBox', '0 0 14 14');
|
143
|
+
svgIcon.setAttribute('fill', 'none');
|
144
|
+
|
145
|
+
const clipPath = document.createElementNS('http://www.w3.org/2000/svg', 'clipPath');
|
146
|
+
clipPath.className = 'clip0_1630_1670';
|
147
|
+
|
148
|
+
const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
|
149
|
+
rect.setAttribute('width', '14');
|
150
|
+
rect.setAttribute('height', '14');
|
151
|
+
rect.setAttribute('fill', 'white');
|
152
|
+
|
153
|
+
const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
154
|
+
path.setAttribute(
|
155
|
+
'd',
|
156
|
+
'M11.9528 2.05329C9.22079 -0.68205 4.78867 -0.68477 2.0533 2.04718C-0.682042 4.7792 -0.684795 9.21135 2.04722 11.9467C4.77917 14.6821 9.21135 14.6848 11.9467 11.9528C14.682 9.22085 14.6848 4.78863 11.9528 2.05329ZM7.00216 11.2406C6.6319 11.2406 6.33174 10.9405 6.33174 10.5702C6.33174 10.1999 6.63187 9.89976 7.00216 9.89976C7.37243 9.89976 7.67259 10.1999 7.67259 10.5702C7.67255 10.9405 7.37243 11.2406 7.00216 11.2406ZM8.09214 7.20401C7.70918 7.42788 7.67645 7.7033 7.6748 8.49691C7.6747 8.54938 7.67453 8.60233 7.67423 8.65558C7.67185 9.03068 7.36712 9.33312 6.99253 9.33312C6.99105 9.33312 6.98957 9.33312 6.98813 9.33312C6.61159 9.33074 6.3083 9.02356 6.31066 8.64699C6.31099 8.59568 6.31109 8.54468 6.31119 8.49415C6.31287 7.67852 6.31492 6.66352 7.40395 6.02694C8.27777 5.51613 8.3879 5.18059 8.28543 4.74029C8.16503 4.2231 7.69273 4.08907 7.32418 4.1312C7.20042 4.14541 6.58322 4.24724 6.58322 4.85783C6.58322 5.23431 6.27795 5.5396 5.90141 5.5396C5.52487 5.5396 5.21964 5.23431 5.21964 4.85783C5.21964 3.76416 6.02107 2.90831 7.16859 2.77656C8.35043 2.64099 9.35515 3.32135 9.61338 4.4312C9.99939 6.08915 8.61379 6.89911 8.09214 7.20401Z',
|
157
|
+
);
|
158
|
+
path.setAttribute('fill', '#c9c8c6');
|
159
|
+
|
160
|
+
clipPath.appendChild(rect);
|
161
|
+
svgIcon.appendChild(clipPath);
|
162
|
+
svgIcon.appendChild(path);
|
163
|
+
|
164
|
+
divFlex.appendChild(spanTitle);
|
165
|
+
divFlex.appendChild(svgIcon);
|
166
|
+
|
167
|
+
const spanInfo = document.createElement('span');
|
168
|
+
spanInfo.id = `${category}ItemsInformation`;
|
169
|
+
spanInfo.className = 'category-information';
|
170
|
+
|
171
|
+
if (category !== 'passed' && categoryData.totalItems !== 0) {
|
172
|
+
spanInfo.textContent = `${categoryData.rules.length} ${categoryData.rules.length === 1 ? 'issue' : 'issues'} / ${categoryData.totalItems} ${categoryData.totalItems === 1 ? 'occurrence' : 'occurrences'}`;
|
173
|
+
} else if (category !== 'passed' && categoryData.totalItems === 0) {
|
174
|
+
spanInfo.textContent = `0 issues`;
|
175
|
+
} else {
|
176
|
+
spanInfo.textContent = `${categoryData.totalItems} ${categoryData.totalItems === 1 ? 'occurrence' : 'occurrences'}`;
|
177
|
+
}
|
178
|
+
|
179
|
+
button.appendChild(divFlex);
|
180
|
+
button.appendChild(spanInfo);
|
181
|
+
listItem.appendChild(button);
|
182
|
+
scategoryList.appendChild(listItem);
|
183
|
+
}
|
184
|
+
});
|
185
|
+
|
186
|
+
const categoryList = document.getElementById('issueTypeListbox');
|
187
|
+
|
188
|
+
Object.keys(scanItems).forEach(category => {
|
189
|
+
if (category !== 'passed') {
|
190
|
+
const categoryData = scanItems[category];
|
191
|
+
const rulesLength = categoryData.rules ? categoryData.rules.length : 0;
|
192
|
+
|
193
|
+
const listItem = document.createElement('li');
|
194
|
+
listItem.tabIndex = -1;
|
195
|
+
listItem.id = `${category}DropdownSelector`;
|
196
|
+
listItem.className = `${category} category-selector d-flex flex-row align-items-center gap-2 position-relative`;
|
197
|
+
listItem.role = 'option';
|
198
|
+
|
199
|
+
const spanTitle = document.createElement('span');
|
200
|
+
spanTitle.id = `${category}Title`;
|
201
|
+
spanTitle.className = 'd-flex align-items-center category-name fw-bold d-inline mb-0';
|
202
|
+
spanTitle.textContent = formattedCategoryTitles[category];
|
203
|
+
|
204
|
+
const spanInfo = document.createElement('span');
|
205
|
+
spanInfo.id = `${category}ItemsInformation`;
|
206
|
+
spanInfo.className = 'category-information';
|
207
|
+
|
208
|
+
if (category !== 'passed' && categoryData.totalItems !== 0) {
|
209
|
+
spanInfo.textContent = `(${categoryData.rules.length} ${categoryData.rules.length === 1 ? 'issue' : 'issues'})`;
|
210
|
+
} else if (category !== 'passed' && categoryData.totalItems === 0) {
|
211
|
+
spanInfo.textContent = `(0 issues)`;
|
212
|
+
} else {
|
213
|
+
spanInfo.textContent = `(${categoryData.totalItems} ${categoryData.totalItems === 1 ? 'occurrence' : 'occurrences'})`;
|
214
|
+
}
|
215
|
+
|
216
|
+
listItem.appendChild(spanTitle);
|
217
|
+
listItem.appendChild(spanInfo);
|
218
|
+
categoryList.appendChild(listItem);
|
219
|
+
}
|
220
|
+
});
|
221
|
+
};
|
222
|
+
|
223
|
+
const scanDataHTML = () => {
|
224
|
+
const formattedViewerLocalStartTime = formatAboutStartTime(scanData.startTime);
|
225
|
+
document.getElementById('aboutStartTime').innerHTML = formattedViewerLocalStartTime;
|
226
|
+
document.getElementById('urlScanned').innerHTML = scanData.urlScanned;
|
227
|
+
document.getElementById('urlScanned').href = scanData.urlScanned;
|
228
|
+
document.getElementById('viewport').innerHTML = scanData.viewport.startsWith('CustomWidth')
|
229
|
+
? `${scanData.viewport.split('_')[1]} width viewport`
|
230
|
+
: scanData.viewport + ' viewport';
|
231
|
+
document.getElementById('pagesScannedModalToggleTxt').innerHTML = scanData.isCustomFlow
|
232
|
+
? scanData.customFlowLabel +
|
233
|
+
' (' +
|
234
|
+
scanData.totalPagesScanned +
|
235
|
+
' ' +
|
236
|
+
(scanData.totalPagesScanned === 1 ? 'page' : 'pages') +
|
237
|
+
')'
|
238
|
+
: scanData.scanType +
|
239
|
+
' crawl' +
|
240
|
+
' (' +
|
241
|
+
scanData.totalPagesScanned +
|
242
|
+
' ' +
|
243
|
+
(scanData.totalPagesScanned === 1 ? 'page' : 'pages') +
|
244
|
+
')';
|
245
|
+
|
246
|
+
var itemsElement = document.getElementById('items');
|
247
|
+
var failedItems = scanItems.mustFix.totalItems + scanItems.goodToFix.totalItems;
|
248
|
+
var passedItems = scanItems.passed.totalItems;
|
249
|
+
var itemsContent = `${failedItems} ${failedItems === 1 ? 'occurrence' : 'occurrences'} failed,<br>
|
250
|
+
<a href="#" id="createPassedItemsFile">${passedItems} ${passedItems === 1 ? 'occurrence' : 'occurrences'} passed</a>`;
|
251
|
+
itemsElement.innerHTML = itemsContent;
|
252
|
+
|
253
|
+
var phAppVersionElement = document.getElementById('phAppVersion');
|
254
|
+
var versionContent = 'Oobee Version ' + scanData.phAppVersion;
|
255
|
+
phAppVersionElement.innerHTML = versionContent;
|
256
|
+
|
257
|
+
var isCustomFlow = scanData.isCustomFlow;
|
258
|
+
var pagesScanned = scanData.pagesScanned;
|
259
|
+
var pagesScannedList = document.getElementById('pagesScannedList');
|
260
|
+
|
261
|
+
pagesScanned.forEach((page, index) => {
|
262
|
+
var listItem = document.createElement('li');
|
263
|
+
|
264
|
+
if (isCustomFlow) {
|
265
|
+
listItem.innerHTML = `
|
266
|
+
<div class="custom-flow-screenshot-container">
|
267
|
+
<img
|
268
|
+
src="${page.pageImagePath}"
|
269
|
+
alt="Screenshot of ${page.url}"
|
270
|
+
class="custom-flow-screenshot"
|
271
|
+
onerror="this.onerror = null; this.remove();"
|
272
|
+
>
|
273
|
+
<div class="display-url-container">
|
274
|
+
<a href="${page.url}" target="_blank">${page.pageTitle.length > 0 ? page.pageTitle : page.url}</a>
|
275
|
+
<p>${page.url}</p>
|
276
|
+
</div>
|
277
|
+
</div>
|
278
|
+
`;
|
279
|
+
} else {
|
280
|
+
listItem.innerHTML = `
|
281
|
+
<a href="${page.url}" target="_blank">${page.pageTitle.length > 0 ? page.pageTitle : page.url}</a>
|
282
|
+
<p>${page.url}</p>
|
283
|
+
`;
|
284
|
+
}
|
285
|
+
|
286
|
+
pagesScannedList.appendChild(listItem);
|
287
|
+
});
|
288
|
+
|
289
|
+
var totalPagesNotScanned = scanData.totalPagesNotScanned;
|
290
|
+
var pagesNotScanned = scanData.pagesNotScanned;
|
291
|
+
|
292
|
+
var pagesNotScannedList = document.getElementById('pagesNotScannedList');
|
293
|
+
|
294
|
+
// Only update if there are pages not scanned
|
295
|
+
if (totalPagesNotScanned > 0) {
|
296
|
+
document.getElementById('totalPagesScannedLabel').innerHTML = scanData.totalPagesScanned;
|
297
|
+
document.getElementById('totalPagesNotScannedLabel').innerHTML =
|
298
|
+
scanData.totalPagesNotScanned;
|
299
|
+
|
300
|
+
pagesNotScanned.forEach((page, index) => {
|
301
|
+
var listItem = document.createElement('li');
|
302
|
+
listItem.innerHTML = `<a class="not-scanned-url" href="${page.url}" target="_blank">${page.url}</a>`;
|
303
|
+
pagesNotScannedList.appendChild(listItem);
|
304
|
+
});
|
305
|
+
}
|
306
|
+
|
307
|
+
const cypressScanAboutMetadata = scanData.cypressScanAboutMetadata;
|
308
|
+
if (cypressScanAboutMetadata) {
|
309
|
+
const metadataItems = Object.keys(cypressScanAboutMetadata);
|
310
|
+
metadataItems.forEach(key => {
|
311
|
+
var metadataSpan = document.getElementById('cypressScanAboutMetadata');
|
312
|
+
if (metadataSpan) {
|
313
|
+
const metadataTitle = document.createElement('span');
|
314
|
+
metadataTitle.textContent =
|
315
|
+
key[0].toUpperCase() + key.slice(1) + ': ' + cypressScanAboutMetadata[key];
|
316
|
+
}
|
317
|
+
});
|
318
|
+
}
|
319
|
+
|
320
|
+
document.getElementById('pagesScannedModalLabel').innerHTML = scanData.isCustomFlow
|
321
|
+
? scanData.customFlowLabel +
|
322
|
+
' (' +
|
323
|
+
scanData.totalPagesScanned +
|
324
|
+
' ' +
|
325
|
+
(scanData.totalPagesScanned === 1 ? 'page' : 'pages') +
|
326
|
+
')'
|
327
|
+
: scanData.scanType +
|
328
|
+
' crawl' +
|
329
|
+
' (' +
|
330
|
+
scanData.totalPagesScanned +
|
331
|
+
' ' +
|
332
|
+
(scanData.totalPagesScanned === 1 ? 'page' : 'pages') +
|
333
|
+
')';
|
334
|
+
|
335
|
+
scanDataWCAGCompliance();
|
336
|
+
scanDataTop5Card();
|
337
|
+
scanDataCategorySelector();
|
338
|
+
|
339
|
+
const createPassedItemsFile = async () => {
|
340
|
+
const passedItemsJson = {};
|
341
|
+
|
342
|
+
scanItems.passed.rules.forEach(r => {
|
343
|
+
passedItemsJson[r.description] = {
|
344
|
+
totalOccurrencesInScan: r.totalItems,
|
345
|
+
totalPages: r.pagesAffected.length,
|
346
|
+
pages: r.pagesAffected.map(p => ({
|
347
|
+
pageTitle: p.pageTitle,
|
348
|
+
url: p.url,
|
349
|
+
totalOccurrencesInPage: p.items.length,
|
350
|
+
occurrences: p.items,
|
351
|
+
metadata: p.metadata,
|
352
|
+
})),
|
353
|
+
};
|
354
|
+
});
|
355
|
+
|
356
|
+
const jsonString = JSON.stringify(passedItemsJson, null, 4);
|
357
|
+
|
358
|
+
const blob = new Blob([jsonString], { type: 'application/json' });
|
359
|
+
|
360
|
+
const link = document.createElement('a');
|
361
|
+
|
362
|
+
link.href = URL.createObjectURL(blob);
|
363
|
+
|
364
|
+
storagePath = scanData.storagePath;
|
365
|
+
|
366
|
+
link.download = `passed_items.json`;
|
367
|
+
|
368
|
+
document.body.appendChild(link);
|
369
|
+
|
370
|
+
link.click();
|
371
|
+
|
372
|
+
document.body.removeChild(link);
|
373
|
+
};
|
374
|
+
|
375
|
+
document.getElementById('createPassedItemsFile').addEventListener('click', async e => {
|
376
|
+
e.preventDefault();
|
377
|
+
await createPassedItemsFile();
|
378
|
+
console.log('click');
|
379
|
+
});
|
380
|
+
};
|
381
|
+
|
382
|
+
const formatAboutStartTime = dateString => {
|
383
|
+
const utcStartTimeDate = new Date(dateString);
|
384
|
+
const formattedStartTime = utcStartTimeDate.toLocaleTimeString('en-GB', {
|
385
|
+
year: 'numeric',
|
386
|
+
month: 'short',
|
387
|
+
day: 'numeric',
|
388
|
+
hour12: false,
|
389
|
+
hour: 'numeric',
|
390
|
+
minute: '2-digit',
|
391
|
+
timeZoneName: 'shortGeneric',
|
392
|
+
});
|
393
|
+
|
394
|
+
const timezoneAbbreviation = new Intl.DateTimeFormat('en', {
|
395
|
+
timeZoneName: 'shortOffset',
|
396
|
+
})
|
397
|
+
.formatToParts(utcStartTimeDate)
|
398
|
+
.find(part => part.type === 'timeZoneName').value;
|
399
|
+
|
400
|
+
//adding a breakline between the time and timezone so it looks neater on report
|
401
|
+
const timeColonIndex = formattedStartTime.lastIndexOf(':');
|
402
|
+
const timePart = formattedStartTime.slice(0, timeColonIndex + 3);
|
403
|
+
const timeZonePart = formattedStartTime.slice(timeColonIndex + 4);
|
404
|
+
const htmlFormattedStartTime = `${timePart}<br>${timeZonePart} ${timezoneAbbreviation}`;
|
405
|
+
|
406
|
+
return htmlFormattedStartTime;
|
407
|
+
};
|
408
|
+
|
409
|
+
document.addEventListener('DOMContentLoaded', () => {
|
410
|
+
initTooltips();
|
411
|
+
scanDataHTML();
|
412
|
+
});
|
413
|
+
</script>
|
414
|
+
<!-- Checks if js runs -->
|
415
|
+
<script>
|
416
|
+
document.getElementById('jsOn').classList.remove('d-none');
|
417
|
+
document.getElementById('jsOffMessage').classList.add('d-none');
|
418
|
+
</script>
|
419
|
+
</body>
|
420
|
+
</html>
|
@@ -0,0 +1,47 @@
|
|
1
|
+
<!doctype html>
|
2
|
+
<html lang="en" id="accessibility-site-report">
|
3
|
+
<head lang="en">
|
4
|
+
<meta charset="UTF-8" />
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
6
|
+
<title>Oobee Scan Summary</title>
|
7
|
+
<link
|
8
|
+
rel="icon"
|
9
|
+
type="image/svg+xml"
|
10
|
+
href="data:image/svg+xml,%3Csvg width='48' height='48' viewBox='0 0 48 48' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M23.5 6C11.7707 6 10 11.1369 10 19.23V28.77C10 36.8631 11.7707 42 23.5 42C35.2293 42 37 36.8631 37 28.77V19.23C37 11.1369 35.2293 6 23.5 6ZM25.4903 14.5985V35.0562H21.5097V12.9438H27.8925L25.4903 14.5985Z' fill='%239021A6'/%3E%3C/svg%3E
|
11
|
+
"
|
12
|
+
/>
|
13
|
+
<%- include('partials/styles/summaryBootstrap') %> <%- include('partials/styles/highlightjs') %>
|
14
|
+
<%- include('partials/styles/styles') %>
|
15
|
+
</head>
|
16
|
+
<body class="d-flex flex-column">
|
17
|
+
<%- include('partials/summaryHeader') %> <%- include('partials/summaryMain') %> <%-
|
18
|
+
include('partials/scripts/popper') %> <%- include('partials/scripts/bootstrap') %> <%-
|
19
|
+
include('partials/scripts/highlightjs') %> <%- include('partials/scripts/utils') %> <%-
|
20
|
+
include('partials/scripts/ruleOffcanvas') %> <%- include('partials/scripts/summaryScanResults')
|
21
|
+
%>
|
22
|
+
<script>
|
23
|
+
const scanItems = <%- JSON.stringify(
|
24
|
+
{
|
25
|
+
...items,
|
26
|
+
passed: {
|
27
|
+
rules: items.passed.rules.map(r => delete r.pagesAffected),
|
28
|
+
...items.passed
|
29
|
+
},
|
30
|
+
}
|
31
|
+
) %>
|
32
|
+
</script>
|
33
|
+
<%- include('partials/scripts/summaryTable') %>
|
34
|
+
<script>
|
35
|
+
document.addEventListener('DOMContentLoaded', function () {
|
36
|
+
var tooltipTriggerList = [].slice.call(
|
37
|
+
document.querySelectorAll('[data-bs-toggle="tooltip"]'),
|
38
|
+
);
|
39
|
+
var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
|
40
|
+
const tooltip = new bootstrap.Tooltip(tooltipTriggerEl);
|
41
|
+
tooltipTriggerEl.addEventListener('mouseleave', () => tooltip.hide());
|
42
|
+
return tooltip;
|
43
|
+
});
|
44
|
+
});
|
45
|
+
</script>
|
46
|
+
</body>
|
47
|
+
</html>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<svg data-toggle="tooltip" title="Attention Deficit" width="9px" height="14px" viewBox="0 0 9 14">
|
2
|
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-linecap="round" stroke-linejoin="round">
|
3
|
+
<g class="{{impact}}-stroke-icon" transform="translate(-76.000000, -104.000000)">
|
4
|
+
<g transform="translate(80.400000, 111.100000) rotate(-90.000000) translate(-80.400000, -111.100000) translate(73.900000, 107.100000)">
|
5
|
+
<polyline points="11.6 2 12.4 2 12.4 6 11.6 6"></polyline>
|
6
|
+
<polyline points="2.4 4 5.2 5.2 5.2 2.8 8 4.4"></polyline>
|
7
|
+
<rect x="0.4" y="0.4" width="9.6" height="7.2"></rect>
|
8
|
+
</g>
|
9
|
+
</g>
|
10
|
+
</g>
|
11
|
+
</svg>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<svg data-toggle="tooltip" title="Blind" width="14px" height="12px" viewBox="0 0 14 12">
|
2
|
+
<g stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
3
|
+
<g class="{{impact}}-stroke-icon" transform="translate(-17.000000, -87.000000)">
|
4
|
+
<g transform="translate(18.000000, 87.600000)">
|
5
|
+
<path d="M0.4,5.6 C0.4,5.6 2.8,1.2 6.4,1.2 C10,1.2 12.4,5.6 12.4,5.6 C12.4,5.6 10,10 6.4,10 C2.8,10 0.4,5.6 0.4,5.6 Z" stroke-linecap="round" stroke-linejoin="round"></path>
|
6
|
+
<circle cx="6.4" cy="5.6" r="2.4"></circle>
|
7
|
+
<line x1="0.8" y1="11.2" x2="12" y2="0" id="Path" stroke-linecap="round" stroke-linejoin="round"></line>
|
8
|
+
</g>
|
9
|
+
</g>
|
10
|
+
</g>
|
11
|
+
</svg>
|