-
Notifications
You must be signed in to change notification settings - Fork 278
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(plugin): add aria-* visualizer plugin #142
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/** | ||
* Allows users to see what screen readers would see. | ||
*/ | ||
|
||
const Plugin = require("../base"); | ||
|
||
const annotate = require("../shared/annotate")("roles"); | ||
|
||
// this will let us get a shorter info panel that just | ||
// lets the user know we are visualizing a Screen Reader View | ||
const PANEL_OPTIONS = { | ||
statusPanelView: true | ||
}; | ||
|
||
const ATTRIBUTES = [ | ||
"role", | ||
"aria-hidden" | ||
]; | ||
|
||
require("./style.less"); | ||
|
||
const formatAttributeForMethodName = (attribute) => { | ||
return attribute.split("-").map(part => `${part[0].toUpperCase()}${part.substr(1)}`).join(""); | ||
} | ||
|
||
class AriaVisualizer extends Plugin { | ||
constructor(...args) { | ||
const options = Object.assign({}, args, { panel: PANEL_OPTIONS }); | ||
|
||
super(options); | ||
|
||
this.ariaAttributes = ATTRIBUTES.reduce((functionMap, attribute) => { | ||
const methodSuffix = formatAttributeForMethodName(attribute); | ||
|
||
functionMap[attribute] = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's probably a much better way to handle this, but I wasn't sure how we'd deal with all the various different approaches you might need to take to visualizing the semantics of some of the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I'm not certain yet how we'd do that either. Might be something that evolves a bit as we add support for different |
||
enable: this[`start${methodSuffix}`], | ||
disable: this[`stop${methodSuffix}`] | ||
}; | ||
|
||
return functionMap; | ||
}, {}); | ||
} | ||
|
||
getTitle() { | ||
return "Screen Reader View"; | ||
} | ||
|
||
getDescription() { | ||
return "View the page as if you were a Screen Reader. See the effects of aria-* and other a11y attributes."; | ||
} | ||
|
||
startAriaHidden(attribute) { | ||
const className = `tota11y-${attribute}-visualized`; | ||
|
||
[...document.querySelectorAll(`[${attribute}="true"]:not(.tota11y)`)].forEach((element) => { | ||
// make sure we aren't visualizing our tota11y DOM | ||
if (!element.closest(".tota11y")) { | ||
element.classList.add(className); | ||
} | ||
}); | ||
} | ||
|
||
stopAriaHidden(attribute) { | ||
const className = `tota11y-${attribute}-visualized`; | ||
|
||
[...document.querySelectorAll(`.${className}`)].forEach((element) => { | ||
element.classList.remove(className); | ||
}); | ||
} | ||
|
||
startRole(attribute) { | ||
[...document.querySelectorAll(`[${attribute}]:not(.tota11y)`)].forEach((element) => { | ||
// make sure we aren't annotating our tota11y DOM | ||
if (!element.closest(".tota11y")) { | ||
annotate.label( | ||
element, | ||
`role: ${element.getAttribute("role")}` | ||
); | ||
} | ||
}); | ||
} | ||
|
||
stopRole() { | ||
annotate.removeAll(); | ||
} | ||
|
||
run() { | ||
// pop up our info panel to let the user know what we're doing | ||
this.summary("Visualizing a11y attributes"); | ||
this.panel.render(); | ||
|
||
Object.keys(this.ariaAttributes).forEach((property) => { | ||
this.ariaAttributes[property].enable(property); | ||
}); | ||
} | ||
|
||
cleanup() { | ||
Object.keys(this.ariaAttributes).forEach((property) => { | ||
this.ariaAttributes[property].disable(property); | ||
}); | ||
} | ||
} | ||
|
||
module.exports = AriaVisualizer; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
@import "../../less/variables.less"; | ||
|
||
.tota11y-aria-hidden-visualized { | ||
visibility: hidden !important; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,12 @@ <h1>Hello, world!</h1> | |
|
||
<p><a class="btn btn-primary btn-lg btn-success" href="#" role="button">Continue</a></p> | ||
|
||
<article id="article"> | ||
<p>This paragraph is visible.</p> | ||
<p id="p-with-hidden">This paragraph has an <span id="span" aria-hidden="true">aria-hidden</span> span.</p> | ||
<p id="hidden-p" aria-hidden="true">This paragraph is aria-hidden.</p> | ||
</article> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That was an error on my part. Should be working as expected after the next |
||
|
||
<p> | ||
<img width="40px" height="40px" src="http://s.gravatar.com/avatar/3517596df161030c3779c532f7844383?s=256" alt="jordan"> | ||
<img width="40px" height="40px" src="http://s.gravatar.com/avatar/3517596df161030c3779c532f7844383?s=256" alt=""> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the comment!