Unverified Commit 9e2a573b authored by Robert Knight's avatar Robert Knight Committed by GitHub

Merge pull request #1436 from hypothesis/aria-sidebar-state

Improve accessability for toggle buttons
parents 5baf03dd eab7dad6
'use strict';
const $ = require('jquery');
const Toolbar = require('../toolbar');
describe('Toolbar', () => {
let container;
/**
* Fake implementation of the `annotator` property of the toolbar instance.
*/
let fakeAnnotator;
let currentToolbar;
function createToolbar() {
const toolbar = new Toolbar(container);
toolbar.annotator = fakeAnnotator;
toolbar.pluginInit();
currentToolbar = toolbar;
return toolbar;
}
function findButton(toolbar, title) {
return toolbar.element[0].querySelector(`[title="${title}"]`);
}
function isPressed(button) {
return button.getAttribute('aria-pressed') === 'true';
}
beforeEach(() => {
// The toolbar currently relies on a bunch of not-obviously public
// properties of the `Sidebar` instance, including the DOM structure :(
fakeAnnotator = {
createAnnotation: sinon.stub(),
frame: $('<div class="annotator-collapsed"></div>'),
hide: sinon.stub(),
options: {
showHighlights: 'always',
openSidebar: false,
},
setAllVisibleHighlights: sinon.stub(),
show: sinon.stub(),
visibleHighlights: true,
};
fakeAnnotator.show.callsFake(() =>
fakeAnnotator.frame.removeClass('annotator-collapsed')
);
fakeAnnotator.hide.callsFake(() =>
fakeAnnotator.frame.addClass('annotator-collapsed')
);
fakeAnnotator.setAllVisibleHighlights.callsFake(state => {
fakeAnnotator.visibleHighlights = state;
currentToolbar.publish('setVisibleHighlights', state);
});
container = document.createElement('div');
});
afterEach(() => {
container.remove();
});
it('shows button for opening and closing sidebar', () => {
const toolbar = createToolbar();
const button = findButton(toolbar, 'Toggle or Resize Sidebar');
assert.ok(button, 'open/close toggle button not found');
assert.isFalse(isPressed(button));
button.click();
assert.called(fakeAnnotator.show);
assert.isTrue(isPressed(button));
button.click();
assert.called(fakeAnnotator.hide);
assert.isFalse(isPressed(button));
});
// nb. The "Close Sidebar" button is only shown when using the "Clean" theme.
it('shows button for closing the sidebar', () => {
const toolbar = createToolbar();
const button = findButton(toolbar, 'Close Sidebar');
button.click();
assert.called(fakeAnnotator.hide);
});
it('shows open/close toggle button as pressed if sidebar is open on startup', () => {
fakeAnnotator.options.openSidebar = true;
const toolbar = createToolbar();
const button = findButton(toolbar, 'Toggle or Resize Sidebar');
assert.isTrue(isPressed(button));
});
it('shows button for toggling highlight visibility', () => {
const toolbar = createToolbar();
const button = findButton(toolbar, 'Toggle Highlights Visibility');
assert.ok(button, 'highlight visibility toggle button not found');
assert.isTrue(isPressed(button));
button.click();
assert.calledWith(fakeAnnotator.setAllVisibleHighlights, false);
assert.isFalse(isPressed(button));
button.click();
assert.calledWith(fakeAnnotator.setAllVisibleHighlights, true);
assert.isTrue(isPressed(button));
});
it('shows highlight button as un-pressed if highlights are hidden on startup', () => {
fakeAnnotator.options.showHighlights = 'never';
const toolbar = createToolbar();
const button = findButton(toolbar, 'Toggle Highlights Visibility');
assert.isFalse(isPressed(button));
});
it('shows button for creating new page notes', () => {
const toolbar = createToolbar();
const button = findButton(toolbar, 'New Page Note');
assert.ok(button, 'page note button not found');
button.click();
assert.called(fakeAnnotator.createAnnotation);
assert.called(fakeAnnotator.show);
});
});
Plugin = require('../plugin')
$ = require('jquery')
makeButton = (item) ->
anchor = $('<button></button>')
.attr('href', '')
.attr('title', item.title)
.attr('name', item.name)
.attr('aria-pressed', item.ariaPressed)
.on(item.on)
.addClass('annotator-frame-button')
.addClass(item.class)
......@@ -27,6 +29,13 @@ module.exports = class Toolbar extends Plugin
else
$(@element).append @toolbar
# Get the parsed configuration to determine the initial state of the buttons.
# nb. This duplicates state that lives elsewhere. To avoid it getting out
# of sync, it would be better if that initial state were passed in.
config = @annotator.options
highlightsAreVisible = config.showHighlights == 'always'
isSidebarOpen = config.openSidebar
items = [
"title": "Close Sidebar"
"class": "annotator-frame-button--sidebar_close h-icon-close"
......@@ -39,6 +48,7 @@ module.exports = class Toolbar extends Plugin
@toolbar.find('[name=sidebar-close]').hide();
,
"title": "Toggle or Resize Sidebar"
"ariaPressed": isSidebarOpen
"class": "annotator-frame-button--sidebar_toggle h-icon-chevron-left"
"name": "sidebar-toggle"
"on":
......@@ -48,12 +58,15 @@ module.exports = class Toolbar extends Plugin
collapsed = @annotator.frame.hasClass('annotator-collapsed')
if collapsed
@annotator.show()
event.target.setAttribute('aria-pressed', true);
else
@annotator.hide()
event.target.setAttribute('aria-pressed', false);
,
"title": "Hide Highlights"
"class": "h-icon-visibility"
"title": "Toggle Highlights Visibility"
"class": if highlightsAreVisible then 'h-icon-visibility' else 'h-icon-visibility-off'
"name": "highlight-visibility"
"ariaPressed": highlightsAreVisible
"on":
"click": (event) =>
event.preventDefault()
......@@ -84,15 +97,15 @@ module.exports = class Toolbar extends Plugin
onSetVisibleHighlights: (state) ->
if state
$('[name=highlight-visibility]')
@element.find('[name=highlight-visibility]')
.removeClass('h-icon-visibility-off')
.addClass('h-icon-visibility')
.prop('title', 'Hide Highlights');
.attr('aria-pressed', 'true')
else
$('[name=highlight-visibility]')
@element.find('[name=highlight-visibility]')
.removeClass('h-icon-visibility')
.addClass('h-icon-visibility-off')
.prop('title', 'Show Highlights');
.attr('aria-pressed', 'false')
disableMinimizeBtn: () ->
$('[name=sidebar-toggle]').remove();
......
......@@ -107,7 +107,7 @@ $base-font-size: 14px;
}
.annotator-frame-button {
transition: background-color 0.25s 0.25s;
transition: background-color 0.25s;
@include smallshadow;
background: $white;
border: solid 1px $gray-lighter;
......@@ -121,7 +121,6 @@ $base-font-size: 14px;
margin-bottom: 5px;
&:active {
transition: background-color 0.25s;
background-color: $gray-light;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment