@govtechsg/oobee 0.10.76 → 0.10.78-alpha1
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/.github/workflows/publish.yml +8 -1
- package/INTEGRATION.md +50 -3
- package/dist/cli.js +252 -0
- package/dist/combine.js +221 -0
- package/dist/constants/cliFunctions.js +306 -0
- package/dist/constants/common.js +1669 -0
- package/dist/constants/constants.js +913 -0
- package/dist/constants/errorMeta.json +319 -0
- package/dist/constants/itemTypeDescription.js +7 -0
- package/dist/constants/oobeeAi.js +121 -0
- package/dist/constants/questions.js +151 -0
- package/dist/constants/sampleData.js +176 -0
- package/dist/crawlers/commonCrawlerFunc.js +428 -0
- package/dist/crawlers/crawlDomain.js +613 -0
- package/dist/crawlers/crawlIntelligentSitemap.js +135 -0
- package/dist/crawlers/crawlLocalFile.js +151 -0
- package/dist/crawlers/crawlSitemap.js +303 -0
- package/dist/crawlers/custom/escapeCssSelector.js +10 -0
- package/dist/crawlers/custom/evaluateAltText.js +11 -0
- package/dist/crawlers/custom/extractAndGradeText.js +44 -0
- package/dist/crawlers/custom/extractText.js +27 -0
- package/dist/crawlers/custom/findElementByCssSelector.js +36 -0
- package/dist/crawlers/custom/flagUnlabelledClickableElements.js +963 -0
- package/dist/crawlers/custom/framesCheck.js +37 -0
- package/dist/crawlers/custom/getAxeConfiguration.js +111 -0
- package/dist/crawlers/custom/gradeReadability.js +23 -0
- package/dist/crawlers/custom/utils.js +1024 -0
- package/dist/crawlers/custom/xPathToCss.js +147 -0
- package/dist/crawlers/guards/urlGuard.js +71 -0
- package/dist/crawlers/pdfScanFunc.js +276 -0
- package/dist/crawlers/runCustom.js +89 -0
- package/dist/exclusions.txt +7 -0
- package/dist/generateHtmlReport.js +144 -0
- package/dist/index.js +62 -0
- package/dist/logs.js +84 -0
- package/dist/mergeAxeResults.js +1588 -0
- package/dist/npmIndex.js +640 -0
- package/dist/proxyService.js +360 -0
- package/dist/runGenerateJustHtmlReport.js +16 -0
- package/dist/screenshotFunc/htmlScreenshotFunc.js +355 -0
- package/dist/screenshotFunc/pdfScreenshotFunc.js +645 -0
- package/dist/services/s3Uploader.js +127 -0
- package/dist/static/ejs/partials/components/allIssues/AllIssues.ejs +9 -0
- package/dist/static/ejs/partials/components/allIssues/CategoryBadges.ejs +82 -0
- package/dist/static/ejs/partials/components/allIssues/FilterBar.ejs +33 -0
- package/dist/static/ejs/partials/components/allIssues/IssuesTable.ejs +41 -0
- package/dist/static/ejs/partials/components/header/SiteInfo.ejs +119 -0
- package/dist/static/ejs/partials/components/header/aboutScanModal/AboutScanModal.ejs +15 -0
- package/dist/static/ejs/partials/components/header/aboutScanModal/ScanConfiguration.ejs +44 -0
- package/dist/static/ejs/partials/components/header/aboutScanModal/ScanDetails.ejs +142 -0
- package/dist/static/ejs/partials/components/prioritiseIssues/IssueDetailCard.ejs +36 -0
- package/dist/static/ejs/partials/components/prioritiseIssues/PrioritiseIssues.ejs +47 -0
- package/dist/static/ejs/partials/components/ruleModal/ruleOffcanvas.ejs +196 -0
- package/dist/static/ejs/partials/components/scannedPagesSegmentedTabs.ejs +48 -0
- package/dist/static/ejs/partials/components/screenshotLightbox.ejs +13 -0
- package/dist/static/ejs/partials/components/shared/InfoAlert.ejs +3 -0
- package/dist/static/ejs/partials/components/summaryScanAbout.ejs +141 -0
- package/dist/static/ejs/partials/components/summaryScanResults.ejs +16 -0
- package/dist/static/ejs/partials/components/summaryTable.ejs +20 -0
- package/dist/static/ejs/partials/components/summaryWcagCompliance.ejs +94 -0
- package/dist/static/ejs/partials/components/topTen.ejs +6 -0
- package/dist/static/ejs/partials/components/wcagCompliance/FailedCriteria.ejs +47 -0
- package/dist/static/ejs/partials/components/wcagCompliance/WcagCompliance.ejs +16 -0
- package/dist/static/ejs/partials/components/wcagCompliance/WcagGaugeBar.ejs +16 -0
- package/dist/static/ejs/partials/components/wcagCoverageDetails.ejs +18 -0
- package/dist/static/ejs/partials/footer.ejs +24 -0
- package/dist/static/ejs/partials/header.ejs +14 -0
- package/dist/static/ejs/partials/main.ejs +29 -0
- package/dist/static/ejs/partials/scripts/allIssues/AllIssues.ejs +376 -0
- package/dist/static/ejs/partials/scripts/bootstrap.ejs +8 -0
- package/dist/static/ejs/partials/scripts/categorySummary.ejs +141 -0
- package/dist/static/ejs/partials/scripts/decodeUnzipParse.ejs +3 -0
- package/dist/static/ejs/partials/scripts/header/SiteInfo.ejs +44 -0
- package/dist/static/ejs/partials/scripts/header/aboutScanModal/AboutScanModal.ejs +51 -0
- package/dist/static/ejs/partials/scripts/header/aboutScanModal/ScanConfiguration.ejs +127 -0
- package/dist/static/ejs/partials/scripts/header/aboutScanModal/ScanDetails.ejs +60 -0
- package/dist/static/ejs/partials/scripts/highlightjs.ejs +335 -0
- package/dist/static/ejs/partials/scripts/popper.ejs +7 -0
- package/dist/static/ejs/partials/scripts/prioritiseIssues/IssueDetailCard.ejs +137 -0
- package/dist/static/ejs/partials/scripts/prioritiseIssues/PrioritiseIssues.ejs +214 -0
- package/dist/static/ejs/partials/scripts/prioritiseIssues/wcagSvgMap.ejs +861 -0
- package/dist/static/ejs/partials/scripts/ruleModal/constants.ejs +957 -0
- package/dist/static/ejs/partials/scripts/ruleModal/itemCardRenderer.ejs +353 -0
- package/dist/static/ejs/partials/scripts/ruleModal/pageAccordionBuilder.ejs +468 -0
- package/dist/static/ejs/partials/scripts/ruleModal/ruleOffcanvas.ejs +306 -0
- package/dist/static/ejs/partials/scripts/ruleModal/utilities.ejs +483 -0
- package/dist/static/ejs/partials/scripts/scannedPagesSegmentedTabs.ejs +35 -0
- package/dist/static/ejs/partials/scripts/screenshotLightbox.ejs +75 -0
- package/dist/static/ejs/partials/scripts/summaryScanResults.ejs +14 -0
- package/dist/static/ejs/partials/scripts/summaryTable.ejs +78 -0
- package/dist/static/ejs/partials/scripts/topTen.ejs +61 -0
- package/dist/static/ejs/partials/scripts/utils.ejs +453 -0
- package/dist/static/ejs/partials/scripts/wcagCompliance/FailedCriteria.ejs +103 -0
- package/dist/static/ejs/partials/scripts/wcagCompliance/WcagGaugeBar.ejs +47 -0
- package/dist/static/ejs/partials/scripts/wcagCompliance.ejs +15 -0
- package/dist/static/ejs/partials/scripts/wcagCoverageDetails.ejs +75 -0
- package/dist/static/ejs/partials/styles/allIssues/AllIssues.ejs +384 -0
- package/dist/static/ejs/partials/styles/bootstrap.ejs +12391 -0
- package/dist/static/ejs/partials/styles/header/SiteInfo.ejs +121 -0
- package/dist/static/ejs/partials/styles/header/aboutScanModal/AboutScanModal.ejs +82 -0
- package/dist/static/ejs/partials/styles/header/aboutScanModal/ScanConfiguration.ejs +50 -0
- package/dist/static/ejs/partials/styles/header/aboutScanModal/ScanDetails.ejs +149 -0
- package/dist/static/ejs/partials/styles/header.ejs +7 -0
- package/dist/static/ejs/partials/styles/highlightjs.ejs +54 -0
- package/dist/static/ejs/partials/styles/prioritiseIssues/IssueDetailCard.ejs +141 -0
- package/dist/static/ejs/partials/styles/prioritiseIssues/PrioritiseIssues.ejs +204 -0
- package/dist/static/ejs/partials/styles/ruleModal/ruleOffcanvas.ejs +456 -0
- package/dist/static/ejs/partials/styles/scannedPagesSegmentedTabs.ejs +46 -0
- package/dist/static/ejs/partials/styles/shared/InfoAlert.ejs +12 -0
- package/dist/static/ejs/partials/styles/styles.ejs +1607 -0
- package/dist/static/ejs/partials/styles/summaryBootstrap.ejs +12458 -0
- package/dist/static/ejs/partials/styles/topTenCard.ejs +44 -0
- package/dist/static/ejs/partials/styles/wcagCompliance/FailedCriteria.ejs +59 -0
- package/dist/static/ejs/partials/styles/wcagCompliance/WcagGaugeBar.ejs +62 -0
- package/dist/static/ejs/partials/styles/wcagCompliance.ejs +36 -0
- package/dist/static/ejs/partials/styles/wcagCoverageDetails.ejs +33 -0
- package/dist/static/ejs/partials/summaryHeader.ejs +70 -0
- package/dist/static/ejs/partials/summaryMain.ejs +49 -0
- package/dist/static/ejs/report.ejs +226 -0
- package/dist/static/ejs/summary.ejs +47 -0
- package/dist/types/types.js +1 -0
- package/dist/utils.js +1070 -0
- package/examples/oobee-cypress-integration-js/cypress/support/e2e.js +36 -6
- package/examples/oobee-cypress-integration-js/cypress.config.js +45 -1
- package/examples/oobee-cypress-integration-ts/cypress.config.ts +47 -1
- package/examples/oobee-cypress-integration-ts/src/cypress/support/e2e.ts +36 -6
- package/examples/oobee-playwright-integration-js/oobee-playwright-demo.js +2 -1
- package/examples/oobee-playwright-integration-ts/src/oobee-playwright-demo.ts +2 -1
- package/examples/oobee-scan-html-demo.js +51 -0
- package/examples/oobee-scan-page-demo.js +40 -0
- package/package.json +9 -3
- package/src/constants/common.ts +2 -2
- package/src/constants/constants.ts +3 -1
- package/src/crawlers/crawlDomain.ts +1 -0
- package/src/crawlers/runCustom.ts +0 -1
- package/src/mergeAxeResults.ts +43 -22
- package/src/npmIndex.ts +500 -131
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
function buildItemCardsWithPagination(accordionId, category, ruleInCategory, page, index) {
|
|
3
|
+
const accordionAIId = `${ruleInCategory.rule}-${category}-accordion-AI-${index}`;
|
|
4
|
+
const buttonAIId = `${ruleInCategory.rule}-${category}-button-AI-${index}`;
|
|
5
|
+
const errorAIId = `${ruleInCategory.rule}-${category}-error-AI-${index}`;
|
|
6
|
+
const genAiAccordionId = `${ruleInCategory.rule}-${category}-genai-accordion-${index}`;
|
|
7
|
+
const genAiButtonId = `${ruleInCategory.rule}-${category}-genai-button-${index}`;
|
|
8
|
+
const genAiErrorId = `${ruleInCategory.rule}-${category}-genai-error-${index}`;
|
|
9
|
+
const accordion = document.getElementById(`${accordionId}-title`).parentElement.parentElement
|
|
10
|
+
.parentElement;
|
|
11
|
+
|
|
12
|
+
const accordionBody = accordion.getElementsByClassName('accordion-body')[0];
|
|
13
|
+
const totalItems = page.items.length;
|
|
14
|
+
let currentItemIndex = 0;
|
|
15
|
+
|
|
16
|
+
// Create pagination controls
|
|
17
|
+
const paginationControls = createPaginationControls(totalItems);
|
|
18
|
+
|
|
19
|
+
// Create container for the single item card
|
|
20
|
+
const itemCardContainer = createElementFromString('<div></div>');
|
|
21
|
+
|
|
22
|
+
// Function to render a specific item
|
|
23
|
+
async function renderItem(itemIndex) {
|
|
24
|
+
const item = page.items[itemIndex];
|
|
25
|
+
const accordionDivToAppendAI = `${accordionAIId}-${itemIndex}`;
|
|
26
|
+
const buttonDivForAiFeedback = `${buttonAIId}-${itemIndex}`;
|
|
27
|
+
const aiErrorDiv = `${errorAIId}-${itemIndex}`;
|
|
28
|
+
const genAiAccordionDiv = `${genAiAccordionId}-${itemIndex}`;
|
|
29
|
+
const genAiButtonDiv = `${genAiButtonId}-${itemIndex}`;
|
|
30
|
+
const genAiErrorDiv = `${genAiErrorId}-${itemIndex}`;
|
|
31
|
+
|
|
32
|
+
const isPurpleAiRule = oobeeAiRules.includes(ruleInCategory.rule);
|
|
33
|
+
let oobeeAiQueryLabel;
|
|
34
|
+
if (isPurpleAiRule) {
|
|
35
|
+
oobeeAiQueryLabel = await checkPurpleAiQueryLabel(ruleInCategory.rule, item.html);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const itemCard = createItemCard(item, isPurpleAiRule, oobeeAiQueryLabel, {
|
|
39
|
+
accordionDivToAppendAI,
|
|
40
|
+
buttonDivForAiFeedback,
|
|
41
|
+
aiErrorDiv,
|
|
42
|
+
genAiAccordionDiv,
|
|
43
|
+
genAiButtonDiv,
|
|
44
|
+
genAiErrorDiv,
|
|
45
|
+
ruleInCategory,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Clear and update the container
|
|
49
|
+
itemCardContainer.replaceChildren(itemCard);
|
|
50
|
+
|
|
51
|
+
// Setup copy button functionality
|
|
52
|
+
setupCopyButton(itemCard, item.xpath);
|
|
53
|
+
|
|
54
|
+
// Highlight code
|
|
55
|
+
hljs.configure({ ignoreUnescapedHTML: true });
|
|
56
|
+
hljs.highlightAll();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Function to update pagination state
|
|
60
|
+
function updatePaginationState() {
|
|
61
|
+
const prevBtn = paginationControls.querySelector('.pagination-prev');
|
|
62
|
+
const nextBtn = paginationControls.querySelector('.pagination-next');
|
|
63
|
+
const pageInput = paginationControls.querySelector('.pagination-page-input');
|
|
64
|
+
|
|
65
|
+
prevBtn.disabled = currentItemIndex === 0;
|
|
66
|
+
nextBtn.disabled = currentItemIndex === totalItems - 1;
|
|
67
|
+
pageInput.value = currentItemIndex + 1;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Setup pagination event handlers
|
|
71
|
+
setupPaginationHandlers(paginationControls, totalItems, {
|
|
72
|
+
onPageChange: newIndex => {
|
|
73
|
+
currentItemIndex = newIndex;
|
|
74
|
+
renderItem(currentItemIndex);
|
|
75
|
+
updatePaginationState();
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// Append pagination and container to accordion body
|
|
80
|
+
accordionBody.appendChild(paginationControls);
|
|
81
|
+
accordionBody.appendChild(itemCardContainer);
|
|
82
|
+
|
|
83
|
+
// Render the first item
|
|
84
|
+
renderItem(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function createPaginationControls(totalItems) {
|
|
88
|
+
return createElementFromString(`
|
|
89
|
+
<div class="item-pagination-controls">
|
|
90
|
+
<div class="mr-1">Occurrence no.</div>
|
|
91
|
+
<button class="pagination-arrow pagination-prev" aria-label="Previous item" disabled>
|
|
92
|
+
<svg width="8" height="12" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
93
|
+
<path d="M7.41 1.41L6 0L0 6L6 12L7.41 10.59L2.83 6L7.41 1.41Z" fill="#4D34BF"/>
|
|
94
|
+
</svg>
|
|
95
|
+
</button>
|
|
96
|
+
<div class="pagination-page-info">
|
|
97
|
+
<input type="number" class="pagination-page-input" value="1" min="1" max="${totalItems}" aria-label="Current page number" />
|
|
98
|
+
</div>
|
|
99
|
+
<button class="pagination-arrow pagination-next" aria-label="Next item" ${totalItems <= 1 ? 'disabled' : ''}>
|
|
100
|
+
<svg width="8" height="12" viewBox="0 0 8 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
101
|
+
<path d="M1.41 0L0 1.41L4.58 6L0 10.59L1.41 12L7.41 6L1.41 0Z" fill="#4D34BF"/>
|
|
102
|
+
</svg>
|
|
103
|
+
</button>
|
|
104
|
+
<div class="mr-1">of ${totalItems}</div>
|
|
105
|
+
</div>
|
|
106
|
+
`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function setupPaginationHandlers(paginationControls, totalItems, callbacks) {
|
|
110
|
+
const prevBtn = paginationControls.querySelector('.pagination-prev');
|
|
111
|
+
const nextBtn = paginationControls.querySelector('.pagination-next');
|
|
112
|
+
const pageInput = paginationControls.querySelector('.pagination-page-input');
|
|
113
|
+
|
|
114
|
+
let currentIndex = 0;
|
|
115
|
+
|
|
116
|
+
prevBtn.addEventListener('click', () => {
|
|
117
|
+
if (currentIndex > 0) {
|
|
118
|
+
currentIndex--;
|
|
119
|
+
callbacks.onPageChange(currentIndex);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
nextBtn.addEventListener('click', () => {
|
|
124
|
+
if (currentIndex < totalItems - 1) {
|
|
125
|
+
currentIndex++;
|
|
126
|
+
callbacks.onPageChange(currentIndex);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
pageInput.addEventListener('change', e => {
|
|
131
|
+
let pageNum = parseInt(e.target.value);
|
|
132
|
+
if (isNaN(pageNum) || pageNum < 1) {
|
|
133
|
+
pageNum = 1;
|
|
134
|
+
} else if (pageNum > totalItems) {
|
|
135
|
+
pageNum = totalItems;
|
|
136
|
+
}
|
|
137
|
+
currentIndex = pageNum - 1;
|
|
138
|
+
callbacks.onPageChange(currentIndex);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
pageInput.addEventListener('keydown', e => {
|
|
142
|
+
if (e.key === 'Enter') {
|
|
143
|
+
e.target.blur();
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function createItemCard(item, isPurpleAiRule, oobeeAiQueryLabel, aiConfig) {
|
|
149
|
+
const isGenAiSupportedRule = ['color-contrast', 'oobee-accessible-label', 'image-alt', 'listitem', 'link-in-text-block', 'target-size'].includes(aiConfig.ruleInCategory.rule);
|
|
150
|
+
const showGenAiUI = window.oobeeGenAiFeatureEnabled && isGenAiSupportedRule;
|
|
151
|
+
|
|
152
|
+
return createElementFromString(`
|
|
153
|
+
<div>
|
|
154
|
+
<div class="d-flex gap-3 flex-column">
|
|
155
|
+
<h3>Where to find this issue</h3>
|
|
156
|
+
${item.screenshotPath ? createScreenshotSection(item.screenshotPath) : ''}
|
|
157
|
+
${item.xpath ? createXpathSection(item.xpath) : ''}
|
|
158
|
+
${createElementSection(item)}
|
|
159
|
+
${
|
|
160
|
+
item.displayNeedsReview
|
|
161
|
+
? `<div class="d-flex justify-content-between g-one">
|
|
162
|
+
<div class="fw-semibold page-item-card-section-title">Details</div>
|
|
163
|
+
<div class="page-item-card-section-content">
|
|
164
|
+
${generateItemMessageElement(item.displayNeedsReview, item.message)}
|
|
165
|
+
</div>
|
|
166
|
+
</div>`
|
|
167
|
+
: ''
|
|
168
|
+
}
|
|
169
|
+
${isPurpleAiRule ? createAiSuggestionSection(item, oobeeAiQueryLabel, aiConfig) : ''}
|
|
170
|
+
${showGenAiUI ? createGenAiSuggestFixSection(item, aiConfig) : ''}
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function createScreenshotSection(screenshotPath) {
|
|
177
|
+
return `
|
|
178
|
+
<div class="hide-on-img-error">
|
|
179
|
+
<div class="d-flex justify-content-between g-one modal-view">
|
|
180
|
+
<div class="fw-semibold">Screenshot</div>
|
|
181
|
+
<div class="page-item-card-section-content bg-grey-w-border">
|
|
182
|
+
<img
|
|
183
|
+
src="${screenshotPath}"
|
|
184
|
+
onerror="this.onerror = null; this.closest('div.hide-on-img-error').remove();"
|
|
185
|
+
alt="Screenshot of affected element" />
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function createXpathSection(xpath) {
|
|
193
|
+
return `
|
|
194
|
+
<div class="d-flex justify-content-between g-one modal-view">
|
|
195
|
+
<div class="fw-semibold">Path</div>
|
|
196
|
+
<div class="page-item-card-section-content">
|
|
197
|
+
<div class="g-one path-container">
|
|
198
|
+
${xpath}
|
|
199
|
+
<button
|
|
200
|
+
aria-label="Copy path to clipboard"
|
|
201
|
+
class="copy-button"
|
|
202
|
+
data-bs-toggle="tooltip"
|
|
203
|
+
data-bs-placement="top"
|
|
204
|
+
data-bs-original-title="Copy"
|
|
205
|
+
>
|
|
206
|
+
<svg width="13" height="15" viewBox="0 0 13 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
207
|
+
<path d="M3.33333 0H11.3333C12.0667 0 12.6667 0.6 12.6667 1.33333V10.6667H11.3333V1.33333H3.33333V0ZM1.33333 2.66667H8.66667C9.4 2.66667 10 3.26667 10 4V13.3333C10 14.0667 9.4 14.6667 8.66667 14.6667H1.33333C0.600001 14.6667 9.53674e-07 14.0667 9.53674e-07 13.3333V4C9.53674e-07 3.26667 0.600001 2.66667 1.33333 2.66667ZM1.33333 13.3333H8.66667V4H1.33333V13.3333Z" fill="#5735DF"/>
|
|
208
|
+
</svg>
|
|
209
|
+
</button>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
`;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function createElementSection(item) {
|
|
217
|
+
return `
|
|
218
|
+
<div class="d-flex justify-content-between g-one modal-view">
|
|
219
|
+
${
|
|
220
|
+
item.html
|
|
221
|
+
? `
|
|
222
|
+
<div class="fw-semibold">HTML element</div>
|
|
223
|
+
<pre class="page-item-card-section-content">
|
|
224
|
+
<code class="language-html">
|
|
225
|
+
${htmlEscapeString(item.html)}
|
|
226
|
+
</code>
|
|
227
|
+
</pre>`
|
|
228
|
+
: `
|
|
229
|
+
<div class="fw-semibold">Location</div>
|
|
230
|
+
<div class="page-item-card-section-content">
|
|
231
|
+
${item.page > 0 ? `Page ${item.page}` : 'Document'}
|
|
232
|
+
</div>`
|
|
233
|
+
}
|
|
234
|
+
</div>
|
|
235
|
+
`;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function createAiSuggestionSection(item, oobeeAiQueryLabel, aiConfig) {
|
|
239
|
+
const { accordionDivToAppendAI, buttonDivForAiFeedback, aiErrorDiv, ruleInCategory } = aiConfig;
|
|
240
|
+
|
|
241
|
+
let aiContent = '';
|
|
242
|
+
if (oobeeAiQueryLabel.hasNetworkError) {
|
|
243
|
+
aiContent = `
|
|
244
|
+
<button
|
|
245
|
+
id="${buttonDivForAiFeedback}"
|
|
246
|
+
class="aiGenerateResponseButton"
|
|
247
|
+
onClick="handleOfflinePurpleAi(
|
|
248
|
+
'${ruleInCategory.rule}',
|
|
249
|
+
'${accordionDivToAppendAI}',
|
|
250
|
+
'${escapeHtmlStringForArg(item.html)}',
|
|
251
|
+
'${buttonDivForAiFeedback}',
|
|
252
|
+
'${aiErrorDiv}')"
|
|
253
|
+
>
|
|
254
|
+
Generate response
|
|
255
|
+
</button>
|
|
256
|
+
<div id="${aiErrorDiv}"></div>
|
|
257
|
+
`;
|
|
258
|
+
} else if (oobeeAiQueryLabel.label) {
|
|
259
|
+
aiContent = `
|
|
260
|
+
<button
|
|
261
|
+
id="${buttonDivForAiFeedback}"
|
|
262
|
+
class="aiGenerateResponseButton"
|
|
263
|
+
onClick="getPurpleAiAnswer(
|
|
264
|
+
'${ruleInCategory.rule}',
|
|
265
|
+
'${accordionDivToAppendAI}',
|
|
266
|
+
'${oobeeAiQueryLabel.label}',
|
|
267
|
+
'${buttonDivForAiFeedback}',
|
|
268
|
+
'${aiErrorDiv}')"
|
|
269
|
+
>
|
|
270
|
+
Generate response
|
|
271
|
+
</button>
|
|
272
|
+
<div id="${aiErrorDiv}"></div>
|
|
273
|
+
`;
|
|
274
|
+
} else {
|
|
275
|
+
aiContent = `
|
|
276
|
+
<span class="processAI">
|
|
277
|
+
Processing AI suggestions, please check back later.
|
|
278
|
+
</span>
|
|
279
|
+
`;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return `
|
|
283
|
+
<div class="d-flex g-one">
|
|
284
|
+
<div class="fw-semibold page-item-card-section-title">AI suggestion</div>
|
|
285
|
+
<div id="${accordionDivToAppendAI}" class="page-item-card-section-content">
|
|
286
|
+
${aiContent}
|
|
287
|
+
</div>
|
|
288
|
+
</div>
|
|
289
|
+
`;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function createGenAiSuggestFixSection(item, aiConfig) {
|
|
293
|
+
const { genAiAccordionDiv, genAiButtonDiv, genAiErrorDiv, ruleInCategory } = aiConfig;
|
|
294
|
+
|
|
295
|
+
return `
|
|
296
|
+
<div class="d-flex g-one genai-fix-section">
|
|
297
|
+
<div class="fw-semibold page-item-card-section-title">Generative AI Fix</div>
|
|
298
|
+
<div id="${genAiAccordionDiv}" class="page-item-card-section-content">
|
|
299
|
+
<button
|
|
300
|
+
id="${genAiButtonDiv}"
|
|
301
|
+
class="genAiSuggestFixButton"
|
|
302
|
+
onClick="generateGenAiSuggestFix(
|
|
303
|
+
'${ruleInCategory.rule}',
|
|
304
|
+
'${genAiAccordionDiv}',
|
|
305
|
+
'${escapeHtmlStringForArg(item.html)}',
|
|
306
|
+
'${genAiButtonDiv}',
|
|
307
|
+
'${genAiErrorDiv}')"
|
|
308
|
+
>
|
|
309
|
+
Gen AI Suggest Fix
|
|
310
|
+
</button>
|
|
311
|
+
<div id="${genAiErrorDiv}"></div>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
`;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function setupCopyButton(itemCard, xpath) {
|
|
318
|
+
const copyButtonElem = itemCard.getElementsByClassName('copy-button')[0];
|
|
319
|
+
if (!copyButtonElem || !xpath) return;
|
|
320
|
+
|
|
321
|
+
const copyTooltipItem = new bootstrap.Tooltip(copyButtonElem);
|
|
322
|
+
const textToCopy = createElementFromString(`<textarea>${xpath}</textarea>`);
|
|
323
|
+
|
|
324
|
+
copyButtonElem.onclick = event => {
|
|
325
|
+
textToCopy.select();
|
|
326
|
+
navigator.clipboard.writeText(textToCopy.value);
|
|
327
|
+
|
|
328
|
+
copyButtonElem.setAttribute('data-bs-original-title', 'Copied');
|
|
329
|
+
copyTooltipItem.update();
|
|
330
|
+
copyTooltipItem.show();
|
|
331
|
+
|
|
332
|
+
setTimeout(() => {
|
|
333
|
+
copyButtonElem.setAttribute('data-bs-original-title', 'Copy');
|
|
334
|
+
copyTooltipItem.update();
|
|
335
|
+
}, 1500);
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
copyButtonElem.onmousedown = event => {
|
|
339
|
+
event.preventDefault();
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Legacy function name for backwards compatibility
|
|
344
|
+
function buildExpandedRuleCategoryContentAccordian(
|
|
345
|
+
accordionId,
|
|
346
|
+
category,
|
|
347
|
+
ruleInCategory,
|
|
348
|
+
page,
|
|
349
|
+
index,
|
|
350
|
+
) {
|
|
351
|
+
buildItemCardsWithPagination(accordionId, category, ruleInCategory, page, index);
|
|
352
|
+
}
|
|
353
|
+
</script>
|