Skip to content
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

Steps to make tota11y more screen-reader friendly and keyboard-accessible #71

Merged
merged 1 commit into from
Sep 27, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions element.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,14 @@ function buildElement(type, props, ...children) {
if (propName === "onClick") {
let handler = props[propName];
$el.click(handler);

// Some passed-in props need to be set with $.attr
// Currently we do this for role and aria-*
} else if (/^aria-/.test(propName) || propName === "role") {
let value = props[propName];
$el.attr(propName, value);

// All other props can go right to $.prop
} else {
let value = props[propName];
$el.prop(propName, value);
Expand Down
16 changes: 10 additions & 6 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,24 @@ class Toolbar {
e.preventDefault();
e.stopPropagation();
$toolbar.toggleClass("tota11y-expanded");
$toolbar.attr("aria-expanded", $toolbar.is(".tota11y-expanded"));
};

let $toggle = (
<a href="#"
className="tota11y-toolbar-toggle"
onClick={handleToggleClick}>
<div className="tota11y-toolbar-logo">
<button aria-controls="tota11y-toolbar"
className="tota11y-toolbar-toggle"
onClick={handleToggleClick}
aria-label="[tota11y] Toggle menu">
<div aria-hidden="true" className="tota11y-toolbar-logo">
{$logo}
</div>
</a>
</button>
);

$toolbar = (
<div className="tota11y tota11y-toolbar">
<div id="tota11y-toolbar" className="tota11y tota11y-toolbar"
role="region"
aria-expanded="false">
<div className="tota11y-toolbar-body">
{$plugins}
</div>
Expand Down
74 changes: 11 additions & 63 deletions less/tota11y.less
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
@import "variables.less";
@import "base.less";

@descriptionWidth: 200px;
@pluginPadding: 12px;
@controlMargin: 15px;
@indicatorSize: 16px;
@indicatorFontSize: 13px;

@togglePadding: 7px;
@toggleCollapsedWidth: 35px;
@toggleHeight: 25px;
Expand All @@ -21,8 +15,10 @@
z-index: @z-index--UI;

&-toggle {
background-color: @darkGray;
display: block;
padding: @togglePadding;
width: 100%;
}

&-logo {
Expand All @@ -44,61 +40,13 @@
}
}

.tota11y-plugins {
&-separator {
font-size: 12px;
margin: @togglePadding @controlMargin 0;
text-transform: uppercase;
}
}

.tota11y-plugin {
.tota11y-no-select;
border-bottom: 1px solid @darkBorderColor;

&-label {
align-items: center;
display: flex;
padding: @pluginPadding @pluginPadding @pluginPadding 0;
margin: 0;

&:hover {
cursor: pointer;
}
}

&-control {
margin: 0 @controlMargin;
}

&-checkbox {
display: none;
}

&-indicator {
border-radius: @indicatorSize;
border: 1px solid @lightBorderColor;
color: transparent;
font-size: @indicatorFontSize;
height: @indicatorSize;
line-height: @indicatorSize;
padding: 0 0 0 1px;
width: @indicatorSize;
}
&-checkbox:checked + &-indicator {
background-color: @kaGreen;
border-color: @kaGreen;
color: white;
}

&-title {
font-weight: bold;
}

&-description {
font-size: @fontSizeSmall;
font-style: italic;
width: @descriptionWidth;
margin-right: 3px;
}
.tota11y-sr-only {
border: 0;
clip: rect(0,0,0,0);
height: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
width: 1px;
}
57 changes: 36 additions & 21 deletions plugins/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
* cleanup: code to run when the plugin is deactivated from the toolbar
*/

let $ = require("jquery");
let InfoPanel = require("./shared/info-panel");
let template = require("../templates/plugin.handlebars");

require("./style.less");

class Plugin {
constructor() {
this.panel = new InfoPanel(this.getTitle());
this.panel = new InfoPanel(this);
this.$checkbox = null;
}

Expand Down Expand Up @@ -51,20 +51,38 @@ class Plugin {
* Renders the plugin view.
*/
render(clickHandler) {
let templateData = {
title: this.getTitle(),
description: this.getDescription()
};

let $plugin = $(template(templateData));

this.$checkbox = $plugin.find(".tota11y-plugin-checkbox");
this.$checkbox.click((e) => {
e.stopPropagation();
clickHandler(this);
});

return $plugin;
this.$checkbox = (
<input
className="tota11y-plugin-checkbox tota11y-sr-only"
type="checkbox"
onClick={() => clickHandler(this)} />
);

let $switch = (
<label className="tota11y-plugin-switch">
{this.$checkbox}
<div aria-hidden="true"
className="tota11y-plugin-indicator">
&#x2713;
</div>
<div className="tota11y-plugin-info">
<div className="tota11y-plugin-title">
{this.getTitle()}
</div>
<div className="tota11y-plugin-description">
{this.getDescription()}
</div>
</div>
</label>
);

let $el = (
<li role="menu-item" className="tota11y-plugin">
{$switch}
</li>
);

return $el;
}

/**
Expand All @@ -82,10 +100,7 @@ class Plugin {
this.cleanup();
this.panel.destroy();

// If we toggle the plugin ourselves, the checkbox will already be
// unchecked. If another plugin becomes active, however, this method
// will be called and will uncheck the checkbox.
this.$checkbox.attr("checked", false);
this.$checkbox.prop("checked", false);
}
}

Expand Down
5 changes: 4 additions & 1 deletion plugins/headings/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,10 @@ class HeadingsPlugin extends Plugin {
}

getDescription() {
return "Highlights headings (<h1>, <h2>, etc) and order violations";
return `
Highlights headings (&lt;h1&gt;, &lt;h2&gt;, etc) and
order violations
`;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion plugins/shared/info-panel/error.handlebars
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<li class="tota11y-info-error">
<a href="#" class="tota11y-info-error-scroll">
<a aria-label="Scroll to error" href="#" class="tota11y-info-error-scroll">
<div class="tota11y-info-error-scroll-glyph tota11y-info-error-scroll-lens"></div>
<div class="tota11y-info-error-scroll-glyph tota11y-info-error-scroll-handle"></div>
</a>
Expand Down
60 changes: 45 additions & 15 deletions plugins/shared/info-panel/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,24 @@
let $ = require("jquery");
let annotate = require("../annotate")("info-panel");

let template = require("./template.handlebars");
let errorTemplate = require("./error.handlebars");
let tabTemplate = require("./tab.handlebars");
require("./style.less");

const INITIAL_PANEL_MARGIN_PX = 10;
const COLLAPSED_CLASS_NAME = "tota11y-collapsed";
const HIDDEN_CLASS_NAME = "tota11y-info-hidden";

class InfoPanel {
constructor(title) {
this.title = title;
constructor(plugin) {
this.plugin = plugin;

this.about = null;
this.summary = null;
this.errors = [];

this.$el = null;
}

/**
* Sets the title of the info panel
*/
setTitle(title) {
this.title = title;
}

/**
* Sets the contents of the about section as HTML
*/
Expand All @@ -69,7 +61,16 @@ class InfoPanel {

_addTab(title, html) {
// Create and append a tab marker
let $tab = $(tabTemplate({title}));
let $tab = (
<li className="tota11y-info-tab">
<a className="tota11y-info-tab-anchor" href="#">
<span className="tota11y-info-tab-anchor-text">
{title}
</span>
</a>
</li>
);

this.$el.find(".tota11y-info-tabs").append($tab);

// Create and append the tab content
Expand Down Expand Up @@ -113,6 +114,9 @@ class InfoPanel {
e.preventDefault();
e.stopPropagation();
this.$el.addClass(HIDDEN_CLASS_NAME);

// (a11y) Bring the focus back to the plugin's checkbox
this.plugin.$checkbox.focus();
});

// Append the info panel to the body. In reality we'll likely want
Expand Down Expand Up @@ -183,9 +187,32 @@ class InfoPanel {

let hasContent = false;

this.$el = $(template({
title: this.title,
}));
this.$el = (
<div className="tota11y tota11y-info" tabindex="-1">
<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>
<a aria-label="Close info panel"
href="#"
className="tota11y-info-dismiss-trigger">
&times;
</a>
</span>
</header>
<div className="tota11y-info-body">
<div className="tota11y-info-sections" />
<ul role="tablist" className="tota11y-info-tabs" />
</div>
</div>
);

// Add the appropriate tabs based on which information the info panel
// was provided, then highlight the most important one.
Expand Down Expand Up @@ -319,6 +346,9 @@ class InfoPanel {
this.initAndPosition();
}

// (a11y) Shift focus to the newly-opened info panel
this.$el.focus();

return this.$el;
}

Expand Down
5 changes: 0 additions & 5 deletions plugins/shared/info-panel/tab.handlebars

This file was deleted.

18 changes: 0 additions & 18 deletions plugins/shared/info-panel/template.handlebars

This file was deleted.

Loading