您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Test for assessibility problems
// ==UserScript== // @name A11y // @namespace assessibility.colivre.org // @version 0.3 // @description Test for assessibility problems // @author Aurélio A. Heckert // @match *://*/* // @grant none // ==/UserScript== (function() { 'use strict'; // Test if element has acessibility problems // If there is a problem, call `notify(el, <ERROR|WARN>, '<description string>')` function testA11yEl(el) { var id = el.id if (el.tagName == 'IMG' && emptyVal(el.alt) && emptyVal(el.title)) notify(el, ERROR, 'Image without alt text.', 'https://www.w3.org/WAI/tutorials/images/'); if (el.tagName == 'A' && noText(el)) notify(el, ERROR, 'Link without text.'); if (el.tagName == 'BUTTON' && noText(el)) notify(el, ERROR, 'Button without text.'); if (el.tagName.match(/^H[0-9]$/) && noText(el)) notify(el, ERROR, `Heading ${el.tagName} without text.`); if (el.tagName.match(/^H[0-9]$/) && el.nextSibling && el.nextSibling.tagName && // The next tag are united to this. el.nextSibling.tagName.match(/^H[0-9]$/)) notify(el, WARN, `Skipping heading ${el.tagName}.`, 'https://www.w3.org/WAI/tutorials/page-structure/headings#heading-ranks'); if (el.tagName.match(/^H[0-9]$/) && el.nextSibling && el.nextElementSibling && el.nextSibling.constructor == Text && el.nextSibling.textContent.match(/^\s*$/) && // has no text between, only space. el.nextElementSibling.tagName.match(/^H[0-9]$/)) notify(el, WARN, `Skipping heading ${el.tagName}.`, 'https://www.w3.org/WAI/tutorials/page-structure/headings#heading-ranks'); if (el.tagName.match(/INPUT|TEXTAREA|SELECT/) && !(el.type=='submit' && !emptyVal(el.value)) && !(el.type=='hidden') && !( findAncestor(el, (a)=>a.tagName == 'LABEL') /* it is children of a <label> */ || (id && document.querySelector(`label[for=${id}]`)) /* a <label> points to it */ ) ) notify(el, ERROR, `Formfield ${el.tagName} without label.`, 'http://webaim.org/standards/508/checklist#standardn'); } function noText(el) { var imgs = [] imgs.push.apply(imgs, el.querySelectorAll('img')); return emptyVal(el) && emptyVal(el.title) && emptyVal(imgs.map((img)=> img.alt).join('')) } function findAncestor(el, matchFunc) { while (el = el.parentNode) { if (matchFunc(el)) return el; } return null; } var elements = []; var a11yBox, a11yList, pointer; const ERROR = 'ERROR'; const WARN = 'WARN'; const BOXID = 'a11y-userscript-box'; const $ = function(query) { return document.querySelector(query) }; const $$ = function(query) { return document.querySelectorAll(query) }; function emptyVal(val) { if (typeof(val) == 'string') val = val.replace(/\s/g, ''); return typeof(val) == 'undefined' || val == null || val.length == 0 } function mk(tag, attrs) { tag = document.createElement(tag); for (var attName in attrs) { var attVal = attrs[attName]; if (attName == 'children') attVal.forEach(([t,a])=> { mk(t, Object.assign(a, {parent: tag})); }); else if (attName == 'parent') attVal.appendChild(tag); else if (attName == 'text') tag.innerText = attVal; else if (attName == 'html') tag.innerHTML = attVal; else if (attName.match(/^on/)) tag[attName] = attVal; else tag.setAttribute(attName, attVal); } return tag; } function buildA11yBox() { a11yBox = mk('div', { parent: document.body, id: BOXID, class: BOXID+'-toggle-min', children: [ ['i',{ id: BOXID+'-toggle-min-bt', onclick: toggleMin }] ] }); a11yList = mk('ul', {parent: a11yBox}); mk('style', { parent: document.documentElement.firstElementChild, html: ` #${BOXID} {position: fixed; bottom: 0; right: 0; background: rgba(255,255,255,0.7); z-index: 99999; opacity: 1; box-shadow: 0 0 30px rgba(0,0,0,0.6); padding: 15px; border-radius: 15px 0 0 0; color: #000} #${BOXID}-toggle-min-bt::before {content: "\\00d7"; position: absolute; top: 2px; left: 2px; display: block; text-align: center; border: 1px solid #CCC; border-radius: 30px; font-size: 24px; line-height: 24px; width: 24px; background: #EEE; cursor: pointer} #${BOXID} ul {margin: 0; padding: 0; border: 1px solid rgba(0,0,0,0.2); border-top:none; max-height: 90vh; overflow: auto} #${BOXID} li {margin: 0; padding: 6px 10px; border-top: 1px solid rgba(0,0,0,0.1); list-style: none; cursor: pointer} .${BOXID}-toggle-min {opacity: 40%} .${BOXID}-toggle-min ul {display: none} .${BOXID}-ERROR {background: rgba(255,200,200,0.8)} .${BOXID}-WARN {background: rgba(255,250,200,0.8)} #${BOXID} li span { font-size: 70%; padding-right: 1em } #${BOXID} li p { display: inline; margin: 0 } #${BOXID} li a { display: inline-block; margin: 0 0 0 3px; padding: 1px 2px; text-decoration: none; border: 1px solid rgba(0,0,0,0.2); border-radius: 3px; color: #000 } #${BOXID}-pointer { position: absolute; left: -1000px; z-index: 99990; border: 2px dashed #FFF; box-shadow: 0 0 110px 25px rgba(0,0,0,0.6) } #${BOXID}-pointer i { position: absolute; color: red; text-shadow: 1px 1px 1px #000, 0 0 8px #000; font-size: 90px; line-height: 90px; text-align: center } #${BOXID}-pointer-N { top: -90px; width: 100% } #${BOXID}-pointer-S { bottom: -90px; width: 100% } #${BOXID}-pointer-W { left: -90px } #${BOXID}-pointer-E { right: -90px } ` }); pointer = mk('div', { parent: document.body, id: BOXID+'-pointer', children: [ ['i', {id: BOXID+'-pointer-N', text: '↓'}], ['i', {id: BOXID+'-pointer-S', text: '↑'}], ['i', {id: BOXID+'-pointer-W', text: '→'}], ['i', {id: BOXID+'-pointer-E', text: '←'}] ] }); } function toggleMin() { a11yBox.className = (a11yBox.className.length > 0)? '' : BOXID+'-toggle-min'; } function notificationClick(notification, el) { var rect = el.getBoundingClientRect(); var x = parseInt(rect.left + window.pageXOffset - 2); var y = parseInt(rect.top + window.pageYOffset - 2); var w = parseInt(rect.width + 4); var h = parseInt(rect.height + 4); pointer.style.left = x + 'px'; pointer.style.top = y + 'px'; pointer.style.width = w + 'px'; pointer.style.height = h + 'px'; $('#'+BOXID+'-pointer-W').style.lineHeight = h + 'px'; $('#'+BOXID+'-pointer-E').style.lineHeight = h + 'px'; window.scrollTo(parseInt(x-screen.width/4), parseInt(y-screen.height/4)); console.log(el); } function notify(el, type, message, helpURL) { if (!a11yBox) buildA11yBox(); if (elements.filter((reg)=> reg.el==el && reg.message==message).length > 0) return; elements.push({ el, message }); var li = mk('li', { parent: a11yList, class: BOXID+'-'+type, onclick: ()=> notificationClick(this, el), children: [ ['span', {text: type}], ['p', {text: message}], ] }); if (helpURL) mk('a', { href: helpURL, target: '_blank', text: 'help', parent: li }); } function walk(el) { if (el.id == BOXID) return; testA11yEl(el); for (var e,i=0; e=el.children[i]; i++) ((e)=> setTimeout(()=> walk(e), 1))(e); } function testPage() { console.log('testing page...'); walk(document.body); } testPage(); setInterval(testPage, 15000); })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址