Commit 82b23e56 authored by Robert Knight's avatar Robert Knight

Add shortcut to toggle highlight visiblity from the guest frame

This provides a convenient way to avoid the distraction of highlights.  This is
particularly useful for screen reader users to avoid the noise of "annotation
start"/"annotation end" announcements when reading through a piece of text that
has been heavily annotated.
parent 5ff51657
import { ListenerCollection } from '../shared/listener-collection'; import { ListenerCollection } from '../shared/listener-collection';
import { PortFinder, PortRPC } from '../shared/messaging'; import { PortFinder, PortRPC } from '../shared/messaging';
import { generateHexString } from '../shared/random'; import { generateHexString } from '../shared/random';
import { matchShortcut } from '../shared/shortcut';
import { Adder } from './adder'; import { Adder } from './adder';
import { TextRange } from './anchoring/text-range'; import { TextRange } from './anchoring/text-range';
...@@ -296,6 +297,10 @@ export class Guest { ...@@ -296,6 +297,10 @@ export class Guest {
} }
}); });
this._listeners.add(this.element, 'keydown', event => {
this._handleShortcut(event);
});
this._listeners.add(window, 'resize', () => this._repositionAdder()); this._listeners.add(window, 'resize', () => this._repositionAdder());
} }
...@@ -427,7 +432,7 @@ export class Guest { ...@@ -427,7 +432,7 @@ export class Guest {
this._sidebarRPC.on( this._sidebarRPC.on(
'setHighlightsVisible', 'setHighlightsVisible',
/** @param {boolean} showHighlights */ showHighlights => { /** @param {boolean} showHighlights */ showHighlights => {
this.setHighlightsVisible(showHighlights); this.setHighlightsVisible(showHighlights, false /* notifyHost */);
} }
); );
...@@ -766,10 +771,20 @@ export class Guest { ...@@ -766,10 +771,20 @@ export class Guest {
* Set whether highlights are visible in the document or not. * Set whether highlights are visible in the document or not.
* *
* @param {boolean} visible * @param {boolean} visible
* @param {boolean} notifyHost - Whether to notify the host frame about this
* change. This should be true unless the request to change highlight
* visibility is coming from the host frame.
*/ */
setHighlightsVisible(visible) { setHighlightsVisible(visible, notifyHost = true) {
setHighlightsVisible(this.element, visible); setHighlightsVisible(this.element, visible);
this._highlightsVisible = visible; this._highlightsVisible = visible;
if (notifyHost) {
this._hostRPC.call('highlightsVisibleChanged', visible);
}
}
get highlightsVisible() {
return this._highlightsVisible;
} }
/** /**
...@@ -801,4 +816,15 @@ export class Guest { ...@@ -801,4 +816,15 @@ export class Guest {
get hoveredAnnotationTags() { get hoveredAnnotationTags() {
return this._hoveredAnnotations; return this._hoveredAnnotations;
} }
/**
* Handle a potential shortcut trigger.
*
* @param {KeyboardEvent} event
*/
_handleShortcut(event) {
if (matchShortcut(event, 'Ctrl+Shift+H')) {
this.setHighlightsVisible(!this._highlightsVisible);
}
}
} }
...@@ -295,6 +295,14 @@ export class Sidebar { ...@@ -295,6 +295,14 @@ export class Sidebar {
.forEach(rpc => rpc.call('clearSelection')); .forEach(rpc => rpc.call('clearSelection'));
}); });
guestRPC.on(
'highlightsVisibleChanged',
/** @param {boolean} visible */
visible => {
this.setHighlightsVisible(visible);
}
);
// The listener will do nothing if the sidebar doesn't have a bucket bar // The listener will do nothing if the sidebar doesn't have a bucket bar
// (clean theme) // (clean theme)
const bucketBar = this.bucketBar; const bucketBar = this.bucketBar;
......
...@@ -1414,4 +1414,32 @@ describe('Guest', () => { ...@@ -1414,4 +1414,32 @@ describe('Guest', () => {
assert.isTrue(guest.sideBySideActive); assert.isTrue(guest.sideBySideActive);
}); });
}); });
describe('keyboard shortcuts', () => {
it('toggles highlights when shortcut is pressed', () => {
const guest = createGuest();
guest.setHighlightsVisible(true, false /* notifyHost */);
assert.equal(guest.highlightsVisible, true);
guest.element.dispatchEvent(
new KeyboardEvent('keydown', {
ctrlKey: true,
shiftKey: true,
key: 'h',
})
);
assert.equal(guest.highlightsVisible, false);
assert.calledWith(hostRPC().call, 'highlightsVisibleChanged', false);
guest.element.dispatchEvent(
new KeyboardEvent('keydown', {
ctrlKey: true,
shiftKey: true,
key: 'h',
})
);
assert.equal(guest.highlightsVisible, true);
assert.calledWith(hostRPC().call, 'highlightsVisibleChanged', true);
});
});
}); });
...@@ -318,6 +318,18 @@ describe('Sidebar', () => { ...@@ -318,6 +318,18 @@ describe('Sidebar', () => {
assert.neverCalledWith(guestRPC(1).call, 'clearSelection'); assert.neverCalledWith(guestRPC(1).call, 'clearSelection');
assert.calledWith(guestRPC(2).call, 'clearSelection'); assert.calledWith(guestRPC(2).call, 'clearSelection');
}); });
it('updates state of highlights-visible button when state is changed in guest', () => {
const sidebar = createSidebar();
connectGuest(sidebar);
assert.isFalse(fakeToolbar.highlightsVisible);
emitGuestEvent('highlightsVisibleChanged', true);
assert.isTrue(fakeToolbar.highlightsVisible);
emitGuestEvent('highlightsVisibleChanged', false);
assert.isFalse(fakeToolbar.highlightsVisible);
});
}); });
describe('events from sidebar frame', () => { describe('events from sidebar frame', () => {
......
...@@ -16,7 +16,13 @@ export type GuestToHostEvent = ...@@ -16,7 +16,13 @@ export type GuestToHostEvent =
/** /**
* The guest informs the host that the anchors have been changed in the main annotatable frame. * The guest informs the host that the anchors have been changed in the main annotatable frame.
*/ */
| 'anchorsChanged'; | 'anchorsChanged'
/**
* Visibility of highlights was toggled from the guest frame (it can also be
* toggled from the host frame).
*/
| 'highlightsVisibleChanged';
/** /**
* Events that the guest sends to the sidebar * Events that the guest sends to the sidebar
......
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