Skip to content

Commit

Permalink
feat(plugin): add annotation for tabIndex simulation to focus tracker
Browse files Browse the repository at this point in the history
  • Loading branch information
ericrallen committed May 19, 2019
1 parent 95bb6ec commit 8e1e6e7
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 26 deletions.
28 changes: 21 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 33 additions & 7 deletions plugins/focus-tracker/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

let Plugin = require("../base");

let annotate = require("../shared/annotate")("tabIndex");

const FOCUS_EVENT = "focusin";
const BLUR_EVENT = "focusout";

Expand Down Expand Up @@ -39,6 +41,12 @@ class FocusTracker extends Plugin {
const options = Object.assign({}, args, { panel: PANEL_OPTIONS });

super(options);

this.tabIndex = -1;
this.tabOrder = {};
this.generatedIds = [];

this.applyFocusClass = this.applyFocusClass.bind(this);
}

getTitle() {
Expand All @@ -56,21 +64,31 @@ class FocusTracker extends Plugin {
// remove any focused or was-focused indicators on the element
removeFocusClasses(target);

// choose the class we want to add to this element
// based on whether this is the focusin or focusout event
const classToAdd = FOCUS_STATES[type];

// we want to ignore our tota11y toggle and panel because
// the user probably only cares about focusable elements on
// their page getting this visual treatment
if (type === FOCUS_EVENT || target.closest(`.${IGNORE_WAS_FOCUSED_CLASS}`) === null) {
target.classList.add(classToAdd);
if (type === FOCUS_EVENT && !target.closest(`.${IGNORE_WAS_FOCUSED_CLASS}`)) {
// choose the class we want to add to this element
// based on whether this is the focusin or focusout event
const classToAdd = FOCUS_STATES[type];

const id = target.dataset.focusTrackerId || `focusable-element-${new Date().getTime()}`;

if (typeof this.tabOrder[id] === "undefined") {
target.dataset.focusTrackerId = id;

this.tabOrder[id] = this.tabIndex++;

annotate.label(target, `#${(target.tabIndex === -1) ? "-1" : this.tabIndex}`);
}

target.classList.add(classToAdd);
}
}

run() {
// pop up our info panel to let the user know what we're doing
this.summary("Tracking Focus");
this.summary("Tracking Focus. TabIndex starts w/ current focus.");
this.panel.render();

// dynamically apply our event listeners by looping through
Expand All @@ -81,6 +99,9 @@ class FocusTracker extends Plugin {
}

cleanup() {
// clear annotations
annotate.removeAll();

// dynamically remove our event listeners by looping through
// our defined focus states and removing the event handler
Object.keys(FOCUS_STATES).forEach((key) => {
Expand All @@ -91,6 +112,11 @@ class FocusTracker extends Plugin {
removeFocusClasses(element);
});
});

// clean up our focus order data-* ids
[...document.querySelectorAll("[data-focus-tracker-id]")].forEach((element) => {
delete element.dataset.focusTrackerId;
});
}
}

Expand Down
19 changes: 15 additions & 4 deletions plugins/shared/annotate/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ require("./style.less");
// and across.
const MIN_HIGHLIGHT_SIZE = 25;

// typecast to jQuery collection in case our plugin is jquery-less
const ensureJqueryCollection = (el) => (el instanceof $) ? el : $(el);

// Polyfill fallback for IE < 10
window.requestAnimationFrame = window.requestAnimationFrame ||
function(callback) {
Expand Down Expand Up @@ -102,7 +105,9 @@ module.exports = (namespace) => {
return {
// Places a small label in the top left corner of a given jQuery
// element. By default, this label contains the element's tagName.
label($el, text=$el.prop("tagName").toLowerCase()) {
label(el, text=$el.prop("tagName").toLowerCase()) {
const $el = ensureJqueryCollection(el);

let $label = createAnnotation($el, "tota11y-label");
return $label.html(text);
},
Expand All @@ -115,7 +120,9 @@ module.exports = (namespace) => {
// object will contain a "show()" method when the info panel is
// rendered, allowing us to externally open the entry in the info
// panel corresponding to this error.
errorLabel($el, text, expanded, errorEntry) {
errorLabel(el, text, expanded, errorEntry) {
const $el = ensureJqueryCollection(el);

let $innerHtml = $(errorLabelTemplate({
text: text,
detail: expanded,
Expand Down Expand Up @@ -143,7 +150,9 @@ module.exports = (namespace) => {

// Highlights a given jQuery element by placing a translucent
// rectangle directly over it
highlight($el) {
highlight(el) {
const $el = ensureJqueryCollection(el);

let $highlight = createAnnotation($el, "tota11y-highlight");
return $highlight.css({
// include margins
Expand All @@ -154,7 +163,9 @@ module.exports = (namespace) => {

// Toggles a highlight on a given jQuery element `$el` when `$trigger`
// is hovered (mouseenter/mouseleave) or focused (focus/blur)
toggleHighlight($el, $trigger) {
toggleHighlight(el, $trigger) {
const $el = ensureJqueryCollection(el);

let $highlight;

$trigger.on("mouseenter focus", () => {
Expand Down
26 changes: 18 additions & 8 deletions plugins/shared/info-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,23 @@ class InfoPanel {
});
}

renderAnnotationCheckbox() {
if (!this.options.disableAnnotation) {
return (
<label className="tota11y-info-annotation-toggle">
Annotate:
{" "}
<input
className="toggle-annotation"
type="checkbox"
checked="checked" />
</label>
);
}

return null;
}

render() {
// Destroy the existing info panel to prevent double-renders
if (this.$el) {
Expand All @@ -200,14 +217,7 @@ class InfoPanel {
<header className="tota11y-info-title">
{this.plugin.getTitle()}
<span className="tota11y-info-controls">
<label className="tota11y-info-annotation-toggle">
Annotate:
{" "}
<input
className="toggle-annotation"
type="checkbox"
checked="checked" />
</label>
{this.renderAnnotationCheckbox()}
<a aria-label="Close info panel"
href="#"
className="tota11y-info-dismiss-trigger">
Expand Down
6 changes: 6 additions & 0 deletions test/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -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 a <span id="span" aria-hidden="true">hidden</span> span.</p>
<p id="hidden-p" aria-hidden="true">This paragraph is hidden.</p>
</article>

<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="">
Expand Down

0 comments on commit 8e1e6e7

Please sign in to comment.