generated from adobe/aem-boilerplate
-
Notifications
You must be signed in to change notification settings - Fork 177
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'stage' into dc0944stickybanner
- Loading branch information
Showing
3 changed files
with
212 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,58 +1,132 @@ | ||
import { html, signal, useEffect } from '../../../deps/htm-preact.js'; | ||
|
||
const DEF_ICON = 'purple'; | ||
const DEF_DESC = 'Checking...'; | ||
const pass = 'green'; | ||
const fail = 'red'; | ||
const decorativeImages = signal([]); | ||
const altTextImages = signal([]); | ||
const altResult = signal({ title: 'Image alt value', description: DEF_DESC }); | ||
const groups = [ | ||
{ title: 'Images with alt text', imgArray: altTextImages }, | ||
{ title: 'Decorative images (empty alt text)', imgArray: decorativeImages, closed: true }, | ||
]; | ||
const filterOptions = [ | ||
{ value: '', content: 'All' }, | ||
{ value: 'show-main', content: 'Main content', selected: true }, | ||
{ value: 'show-gnav', content: 'Gnav' }, | ||
{ value: 'show-footer', content: 'Footer' }, | ||
]; | ||
|
||
const content = signal({}); | ||
const altResult = signal({ icon: DEF_ICON, title: 'Image alt value', description: DEF_DESC }); | ||
function filterGrid(e) { | ||
const imgGrid = e.target.parentElement.parentElement; | ||
filterOptions.forEach((option) => { | ||
if (imgGrid.classList.contains(option.value)) { | ||
imgGrid.classList.remove(option.value); | ||
} | ||
}); | ||
if (e.target.value) imgGrid.classList.add(e.target.value); | ||
} | ||
|
||
function toggleGrid(e) { | ||
e.preventDefault(); | ||
const clickArea = e.target.nodeName === 'SPAN' ? e.target.parentElement.parentElement : e.target.parentElement; | ||
clickArea.classList.toggle('is-closed'); | ||
} | ||
|
||
function dropdownOptions(props) { | ||
const selected = props.option.selected === true; | ||
return html` | ||
<option value="${props.option.value}" selected="${selected}">${props.option.content}</option> | ||
`; | ||
} | ||
|
||
async function checkAlt() { | ||
const main = document.querySelector('main'); | ||
const images = main.querySelectorAll('img'); | ||
if (altResult.value.checked) return; | ||
// If images are not scoped, tracking pixel/images are picked up. | ||
const images = document.querySelectorAll('header img, main img, footer img'); | ||
const result = { ...altResult.value }; | ||
const imagesWithoutAlt = []; | ||
if (!images) return; | ||
|
||
images.forEach((img) => { | ||
const alt = img.getAttribute('alt'); | ||
if (!alt || alt.trim() === '') { | ||
imagesWithoutAlt.push(img.getAttribute('src')); | ||
let parent = ''; | ||
|
||
if (img.closest('header')) parent = 'gnav'; | ||
if (img.closest('main')) parent = 'main-content'; | ||
if (img.closest('footer')) parent = 'footer'; | ||
if (alt === '') { | ||
img.dataset.altCheck = 'decorative'; | ||
decorativeImages.value = [...decorativeImages.value, | ||
{ | ||
src: img.getAttribute('src'), | ||
altCheck: img.dataset.altCheck, | ||
parent, | ||
}]; | ||
} | ||
if (alt) { | ||
altTextImages.value = [...altTextImages.value, | ||
{ | ||
src: img.getAttribute('src'), | ||
alt, | ||
parent, | ||
}]; | ||
} | ||
img.dataset.pageLocation = parent; | ||
}); | ||
if (!imagesWithoutAlt.length) { | ||
result.icon = pass; | ||
result.description = 'Reason: All images are valid'; | ||
} else { | ||
result.icon = fail; | ||
result.description = 'Reason: Alt text missing for the following images:'; | ||
} | ||
content.value = imagesWithoutAlt; | ||
altResult.value = result; | ||
result.description = 'All images listed below. Please validate each alt text has been set appropriately. Decorative images have been highlighted in yellow on the page.'; | ||
altResult.value = { ...result, checked: true }; | ||
} | ||
|
||
function AccessibilityItem({ icon, title, description }) { | ||
function AccessibilityItem({ title, description }) { | ||
return html` | ||
<div class="access-item"> | ||
<div class="result-icon ${icon}"></div> | ||
<div class=seo-item-text> | ||
<p class=seo-item-title>${title}</p> | ||
<p class=seo-item-description>${description}</p> | ||
<div class=access-item-text> | ||
<p class=access-item-title>${title}</p> | ||
<p class=access-item-description>${description}</p> | ||
</div> | ||
</div>`; | ||
} | ||
|
||
function ImageGroups({ group }) { | ||
const setFilterView = filterOptions.find((option) => option.selected === true); | ||
const { imgArray, closed } = group; | ||
return html` | ||
<div class='grid-heading ${closed === true ? 'is-closed' : ''}'> | ||
<a href='#' onClick=${(e) => toggleGrid(e)} class='grid-toggle'> | ||
<span class="preflight-group-expand"></span> | ||
${group.title} | ||
</a> | ||
</div> | ||
${imgArray.value.length > 0 && html` | ||
<div class="access-image-grid ${setFilterView.value}"> | ||
<div class="access-image-grid-item filter"> | ||
Filter images by: | ||
<select onChange=${(e) => filterGrid(e)} class="image-filter"> | ||
${filterOptions.map((option) => html`<${dropdownOptions} option=${option} />`)} | ||
</select> | ||
</div> | ||
${imgArray.value.map((img) => html` | ||
<div class="access-image-grid-item in-${img.parent}"> | ||
<img src="${img.src}" /> | ||
<span>${!img.altCheck ? `Alt=${img.alt}` : `Marked as ${img.altCheck}`}</span> | ||
<span>Located in ${img.parent}</span> | ||
</div>`)} | ||
</div>`} | ||
${!imgArray.value.length && html` | ||
<div class="access-image-grid"> | ||
<div class="access-image-grid-item full-width">No images found</div> | ||
</div> | ||
`} | ||
`; | ||
} | ||
|
||
export default function Accessibility() { | ||
useEffect(() => { checkAlt(); }, []); | ||
|
||
return html` | ||
<div class="access-columns"> | ||
<${AccessibilityItem} icon=${altResult.value.icon} title=${altResult.value.title} description=${altResult.value.description} /> | ||
${content.value.length > 0 && html` | ||
<p class="access-image-header">Images</p> | ||
<div class="access-image-grid"> | ||
${Object.keys(content.value).map((key) => html`<div class="access-image-grid-item"> | ||
<img src="${content.value[key]}"></img></div>`)} | ||
</div> | ||
`} | ||
<${AccessibilityItem} title=${altResult.value.title} description=${altResult.value.description} /> | ||
${groups.map((group) => html`<${ImageGroups} group=${group} />`)} | ||
</div>`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters