gbu-accessibility-package
Version:
Comprehensive accessibility fixes and project optimization for HTML files. Smart context-aware alt text generation, form labels, button names, link names, landmarks, heading analysis, WCAG-compliant role attributes, unused files detection, dead code analy
163 lines (143 loc) • 5 kB
JavaScript
/**
* Accessibility Enhancer
* JavaScript enhancements for better accessibility
*/
class AccessibilityEnhancer {
constructor(config = {}) {
this.config = {
language: config.language || 'ja',
skipLinkText: config.skipLinkText || 'メインコンテンツにスキップ',
...config
};
}
// Generate JavaScript code for accessibility enhancements
generateEnhancementScript() {
return `
/**
* Accessibility Enhancements
* Auto-generated by Accessibility Toolkit
*/
(function () {
'use strict';
// Add accessibility labels to slider pagination buttons
function addSliderAccessibilityLabels() {
setTimeout(function () {
// Find all pagination containers
const paginationContainers = document.querySelectorAll('.splide-custom-pagination, .pagination');
paginationContainers.forEach(function (container) {
const buttons = container.querySelectorAll('button');
buttons.forEach(function (button, index) {
const slideNumber = index + 1;
if (!button.getAttribute('aria-label')) {
button.setAttribute('aria-label', 'スライド' + slideNumber + 'を表示');
}
});
});
// Handle pagination buttons with data-index
const paginationButtons = document.querySelectorAll('[data-index]');
paginationButtons.forEach(function (button) {
const index = button.getAttribute('data-index');
const slideNumber = parseInt(index) + 1;
if (!button.getAttribute('aria-label')) {
button.setAttribute('aria-label', 'スライド' + slideNumber + 'を表示');
}
});
// Add role="img" and aria-label to picture elements in slides
const sliderPictures = document.querySelectorAll('.splide__slide picture, .slide picture');
sliderPictures.forEach(function (picture) {
if (!picture.getAttribute('role')) {
picture.setAttribute('role', 'img');
}
if (!picture.getAttribute('aria-label')) {
const slide = picture.closest('.splide__slide, .slide');
const heading = slide ? slide.querySelector('h4, h3, h2, h1') : null;
const altText = picture.querySelector('img') ? picture.querySelector('img').getAttribute('alt') : '';
let ariaLabel = '';
if (heading && heading.textContent) {
ariaLabel = heading.textContent + 'の画像';
} else if (altText) {
ariaLabel = altText + 'の画像';
} else {
ariaLabel = 'スライド画像';
}
picture.setAttribute('aria-label', ariaLabel);
}
});
}, 1000);
}
// Add skip link for keyboard navigation
function addSkipLink() {
const skipLink = document.createElement('a');
skipLink.href = '#main-content';
skipLink.textContent = '${this.config.skipLinkText}';
skipLink.className = 'skip-link sr-only';
skipLink.style.cssText = \`
position: absolute;
top: -40px;
left: 6px;
background: #000;
color: #fff;
padding: 8px;
text-decoration: none;
z-index: 1000;
border-radius: 4px;
font-size: 14px;
\`;
skipLink.addEventListener('focus', function () {
this.style.top = '6px';
});
skipLink.addEventListener('blur', function () {
this.style.top = '-40px';
});
document.body.insertBefore(skipLink, document.body.firstChild);
}
// Add main content ID for skip link target
function addMainContentId() {
const mainElement = document.querySelector('main');
if (mainElement && !mainElement.id) {
mainElement.id = 'main-content';
}
}
// Fix missing form labels
function fixFormLabels() {
const inputs = document.querySelectorAll('input[type="text"], input[type="email"], input[type="tel"], textarea');
inputs.forEach(function(input) {
if (!input.getAttribute('aria-label') && !input.getAttribute('aria-labelledby')) {
const placeholder = input.getAttribute('placeholder');
if (placeholder) {
input.setAttribute('aria-label', placeholder);
}
}
});
}
// Initialize all enhancements
function init() {
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', function () {
addSkipLink();
addMainContentId();
addSliderAccessibilityLabels();
fixFormLabels();
});
} else {
addSkipLink();
addMainContentId();
addSliderAccessibilityLabels();
fixFormLabels();
}
// Run again after delay for dynamic content
setTimeout(addSliderAccessibilityLabels, 2000);
}
init();
})();
`;
}
// Save enhancement script to file
async saveEnhancementScript(outputPath) {
const fs = require('fs').promises;
const script = this.generateEnhancementScript();
await fs.writeFile(outputPath, script);
return outputPath;
}
}
module.exports = AccessibilityEnhancer;