Don't allow Enter/Tab/Arrows for Autocomplete, if not active

Don't show Autocomplete, if there are no items available
This commit is contained in:
Henrik Giesel 2021-06-28 23:39:46 +02:00
parent bbef2ab6b4
commit a515a9899b
3 changed files with 59 additions and 55 deletions

View File

@ -25,6 +25,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
} }
} }
function isVisible(): boolean {
return (dropdown as any)._menu.classList.contains("show");
}
/* Normally dropdown and trigger are associated with a /* Normally dropdown and trigger are associated with a
/* common ancestor with .dropdown class */ /* common ancestor with .dropdown class */
function createDropdown(element: HTMLElement): Dropdown { function createDropdown(element: HTMLElement): Dropdown {
@ -43,6 +47,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
/* Set custom menu without using common element with .dropdown */ /* Set custom menu without using common element with .dropdown */
(dropdown as any)._menu = menu; (dropdown as any)._menu = menu;
Object.defineProperty(dropdown, "isVisible", { value: isVisible });
} }
return dropdown as Dropdown; return dropdown as Dropdown;

View File

@ -16,9 +16,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { attachId, getName } from "./tags"; import { attachId, getName } from "./tags";
export let size = isApplePlatform() ? 1.6 : 2.0; export let size = isApplePlatform() ? 1.6 : 2.0;
export let tags: TagType[] = [];
export let suggestions = ["en::idioms", "anki::functionality", "math"]; export let tags: TagType[] = [];
export function resetTags(names: string[]): void { export function resetTags(names: string[]): void {
tags = names.map(attachId); tags = names.map(attachId);
@ -35,31 +34,14 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
function onAutocomplete({ detail }) { function onAutocomplete({ detail }) {
const activeTag = tags[active!]; const activeTag = tags[active!];
const autocompletionChoice = detail.choice; const selected = detail.selected;
console.log(autocompletionChoice, activeTag); activeName = selected ?? activeTag.name;
if (autocompletionChoice) {
activeName = autocompletionChoice;
} else {
activeName = activeTag.name;
}
} }
let addOrPop = true; let suggestions: string[] = [];
function updateSuggestions(): void {
if (suggestions.length === 0) {
addOrPop = false;
} else if (suggestions.length > 3) {
addOrPop = true;
}
if (addOrPop) { function updateSuggestions(): void {}
suggestions.pop();
suggestions = suggestions;
} else {
suggestions = suggestions.concat(["another"]);
}
}
function updateWithTagName(tag: TagType): void { function updateWithTagName(tag: TagType): void {
tag.name = activeName; tag.name = activeName;
@ -225,7 +207,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
activeAfterBlur = null; activeAfterBlur = null;
} }
function update(event: KeyboardEvent, autocomplete): void { function update(event: KeyboardEvent, autocomplete: any): void {
const visible = autocomplete.isVisible();
if (
!visible &&
(event.location === KeyboardEvent.DOM_KEY_LOCATION_STANDARD ||
event.location === KeyboardEvent.DOM_KEY_LOCATION_NUMPAD)
) {
autocomplete.show();
}
switch (event.code) { switch (event.code) {
case "ArrowUp": case "ArrowUp":
autocomplete.selectNext(); autocomplete.selectNext();
@ -277,6 +269,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
id={tag.id} id={tag.id}
bind:name={activeName} bind:name={activeName}
bind:input={activeInput} bind:input={activeInput}
on:click={(event) => event.stopPropagation()}
on:focus={() => { on:focus={() => {
activeName = tag.name; activeName = tag.name;
createAutocomplete(activeInput); createAutocomplete(activeInput);

View File

@ -16,7 +16,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
export let suggestions: string[]; export let suggestions: string[];
let dropdown: Dropdown | undefined; let target: HTMLElement;
let dropdown: Dropdown;
let autocomplete: any;
let selected: number | null = null; let selected: number | null = null;
// blue highlight // blue highlight
@ -24,25 +26,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const dispatch = createEventDispatcher(); const dispatch = createEventDispatcher();
const createAutocomplete =
(createDropdown: (target: HTMLElement) => Dropdown) =>
(target: HTMLElement): void => {
dropdown = createDropdown(target);
};
function selectPrevious() {
if (selected === null) {
selected = suggestions.length - 1;
} else if (selected === 0) {
selected = null;
} else {
selected--;
}
const choice = suggestions[selected ?? -1];
dispatch("dropdown", { choice });
}
function selectNext() { function selectNext() {
if (selected === null) { if (selected === null) {
selected = 0; selected = 0;
@ -52,8 +35,19 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
selected++; selected++;
} }
const choice = suggestions[selected ?? -1]; dispatch("autocomplete", { selected: suggestions[selected ?? -1] });
dispatch("autocomplete", { choice }); }
function selectPrevious() {
if (selected === null) {
selected = suggestions.length - 1;
} else if (selected === 0) {
selected = null;
} else {
selected--;
}
dispatch("autocomplete", { selected: suggestions[selected ?? -1] });
} }
function chooseSelected() { function chooseSelected() {
@ -69,20 +63,32 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
if (suggestions.length > 0) { if (suggestions.length > 0) {
dropdown.show(); dropdown.show();
// disabled class will tell Bootstrap not to show menu on clicking
target.classList.remove("disabled");
} else { } else {
dropdown.hide(); dropdown.hide();
target.classList.add("disabled");
} }
} }
const autocomplete = { const createAutocomplete =
hide: () => dropdown!.hide(), (createDropdown: (element: HTMLElement) => Dropdown) =>
show: () => dropdown!.show(), (element: HTMLElement): any => {
toggle: () => dropdown!.toggle(), target = element;
selectPrevious, dropdown = createDropdown(element);
selectNext, autocomplete = {
chooseSelected, hide: dropdown.hide.bind(dropdown),
update, show: dropdown.show.bind(dropdown),
}; toggle: dropdown.toggle.bind(dropdown),
isVisible: (dropdown as any).isVisible,
selectPrevious,
selectNext,
chooseSelected,
update,
};
return autocomplete;
};
onDestroy(() => dropdown?.dispose()); onDestroy(() => dropdown?.dispose());
</script> </script>