1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-07-28 17:02:04 +03:00

Fixed click issue with tag suggestions in safari

Updated selectable elements to be divs instead of buttons since Safari
akwardly does not focus on buttons on click.
Also standardised keyboard handling to our standard nav class.
Also addressed empty tag values showing in results.
For #4139
This commit is contained in:
Dan Brown
2023-04-07 17:47:46 +01:00
parent fd674d10e3
commit e722ee4268
3 changed files with 30 additions and 55 deletions

View File

@ -1,6 +1,7 @@
import {escapeHtml} from "../services/util";
import {onChildEvent} from "../services/dom";
import {Component} from "./component";
import {KeyboardNavigationHandler} from "../services/keyboard-navigation";
const ajaxCache = {};
@ -21,26 +22,31 @@ export class AutoSuggest extends Component {
}
setupListeners() {
const navHandler = new KeyboardNavigationHandler(
this.list,
event => {
this.input.focus();
setTimeout(() => this.hideSuggestions(), 1);
},
event => {
event.preventDefault();
this.selectSuggestion(event.target.textContent);
},
);
navHandler.shareHandlingToEl(this.input);
onChildEvent(this.list, '.text-item', 'click', (event, el) => {
this.selectSuggestion(el.textContent);
});
this.input.addEventListener('input', this.requestSuggestions.bind(this));
this.input.addEventListener('focus', this.requestSuggestions.bind(this));
this.input.addEventListener('blur', this.hideSuggestionsIfFocusedLost.bind(this));
this.input.addEventListener('keydown', event => {
if (event.key === 'Tab') {
this.hideSuggestions();
}
});
this.input.addEventListener('blur', this.hideSuggestionsIfFocusedLost.bind(this));
this.container.addEventListener('keydown', this.containerKeyDown.bind(this));
onChildEvent(this.list, 'button', 'click', (event, el) => {
this.selectSuggestion(el.textContent);
});
onChildEvent(this.list, 'button', 'keydown', (event, el) => {
if (event.key === 'Enter') {
this.selectSuggestion(el.textContent);
}
});
}
selectSuggestion(value) {
@ -52,36 +58,6 @@ export class AutoSuggest extends Component {
this.hideSuggestions();
}
containerKeyDown(event) {
if (event.key === 'Enter') event.preventDefault();
if (this.list.classList.contains('hidden')) return;
// Down arrow
if (event.key === 'ArrowDown') {
this.moveFocus(true);
event.preventDefault();
}
// Up Arrow
else if (event.key === 'ArrowUp') {
this.moveFocus(false);
event.preventDefault();
}
// Escape key
else if (event.key === 'Escape') {
this.hideSuggestions();
event.preventDefault();
}
}
moveFocus(forward = true) {
const focusables = Array.from(this.container.querySelectorAll('input,button'));
const index = focusables.indexOf(document.activeElement);
const newFocus = focusables[index + (forward ? 1 : -1)];
if (newFocus) {
newFocus.focus()
}
}
async requestSuggestions() {
if (Date.now() - this.lastPopulated < 50) {
return;
@ -132,9 +108,11 @@ export class AutoSuggest extends Component {
return this.hideSuggestions();
}
this.list.innerHTML = suggestions.map(value => `<li><button type="button" class="text-item">${escapeHtml(value)}</button></li>`).join('');
// This used to use <button>s but was changed to div elements since Safari would not focus on buttons
// on which causes a range of other complexities related to focus handling.
this.list.innerHTML = suggestions.map(value => `<li><div tabindex="-1" class="text-item">${escapeHtml(value)}</div></li>`).join('');
this.list.style.display = 'block';
for (const button of this.list.querySelectorAll('button')) {
for (const button of this.list.querySelectorAll('.text-item')) {
button.addEventListener('blur', this.hideSuggestionsIfFocusedLost.bind(this));
}
}