Fix keyboard accessibility in conflict-resolution dialog

It's now possible to tab through the panes and the buttons, and
left/right-arrow also change the selection, so you can use Left/Right +
Return to move through multiple conflicts.

Fixes #3395
This commit is contained in:
Dan Stillman 2023-09-06 06:37:13 -04:00
parent ad676adbbb
commit f688183878
3 changed files with 40 additions and 12 deletions

View file

@ -37,6 +37,7 @@
this.hideEmptyFields = false;
this.clickByRow = false;
this.clickByItem = false;
this.preventFocus = false;
this.clickHandler = null;
this.blurHandler = null;
@ -1005,10 +1006,12 @@
}
td.appendChild(addButton);
for (const domEl of [th, toggleButton, removeButton, addButton]) {
domEl.setAttribute('tabindex', '0');
domEl.addEventListener('keypress', this.handleKeyPress.bind(this));
domEl.addEventListener('focusin', this.updateLastFocused.bind(this));
if (!this.preventFocus) {
for (const domEl of [th, toggleButton, removeButton, addButton]) {
domEl.setAttribute('tabindex', '0');
domEl.addEventListener('keypress', this.handleKeyPress.bind(this));
domEl.addEventListener('focusin', this.updateLastFocused.bind(this));
}
}
this._creatorCount++;

View file

@ -51,6 +51,18 @@
this._leftPane = this._id('left-pane');
this._rightPane = this._id('right-pane');
this._mergePane = this._id('merge-pane');
// Select pane with left/right arrow key
this.addEventListener('keypress', (event) => {
if (event.key == "ArrowRight" && !this._rightPane.hasAttribute("selected")) {
this.choosePane(this._rightPane);
this.rightPane.groupbox.focus();
}
else if (event.key == "ArrowLeft" && !this._leftPane.hasAttribute("selected")) {
this.choosePane(this._leftPane);
this._leftPane.groupbox.focus();
}
});
}
get data() {
@ -267,12 +279,12 @@
this.append(document.importNode(this.content, true));
this.parent = document.querySelector('merge-group');
this.isLeftPane = this.id == 'left-pane';
this.isRightPane = this.id == 'right-pane';
this.isMergePane = this.id == 'merge-pane';
if (!this.isMergePane) {
this.box.onclick = function () {
this.parent.choosePane(this);
}.bind(this);
this.groupbox.onclick = this.handleClick.bind(this);
}
}
@ -280,7 +292,7 @@
return this.parent.type;
}
get box() {
get groupbox() {
return this.querySelector('groupbox');
}
@ -326,7 +338,7 @@
var button = this._class('choose-button');
button.label = Zotero.getString('sync.conflict.chooseThisVersion');
if (this.showButton) {
button.onclick = () => this.parent.choosePane(this);
button.onclick = this.handleClick.bind(this);
button.style.visibility = 'visible';
}
else {
@ -403,6 +415,17 @@
objbox.setAttribute("flex", "1");
objbox.mode = this.type == 'file' ? 'filemerge' : 'merge';
// Keyboard accessibility
objbox.preventFocus = true;
if (!this.isMergePane) {
this.groupbox.setAttribute('tabindex', 0);
this.groupbox.addEventListener('keypress', (event) => {
if (event.key == " ") {
this.handleClick();
}
});
}
// Store JSON
this._data = val;
@ -427,8 +450,8 @@
}
}
click() {
this.box.click();
handleClick() {
this.parent.choosePane(this);
}
_class(className) {

View file

@ -93,7 +93,9 @@ merge-group:not([mergetype="note"]) #right-pane:active attachment-box #title {
}
#left-pane:hover:not([selected=true]) h2,
#right-pane:hover:not([selected=true]) h2 {
#left-pane groupbox:focus:not([selected=true]) h2,
#right-pane:hover:not([selected=true]) h2,
#right-pane groupbox:focus:not([selected=true]) h2 {
text-decoration: underline;
}