Pooru/public/js/app.js
Lucas Gabriel Vuotto cc25efc5f4 site: rework {up,down} arrow handling
Allows it to work when setting the cursor via the pointer.
2025-04-28 14:19:01 +00:00

115 lines
2.9 KiB
JavaScript

function getCurrentWordFromCursor(s, cursor) {
return s.substring(s.lastIndexOf(' ', cursor - 1) + 1, cursor);
}
function mySplice(s, idx, del, n) {
return s.substring(0, idx) + n + s.substring(idx + del);
}
document.addEventListener('alpine:init', () => {
Alpine.data('tagsSuggestions', (initialSearch = '') => ({
items: [],
activeItem: null,
search: initialSearch,
cursor: 0,
currentWord: '',
open: false,
get sortedItems() {
return this.items.toSorted((a, b) => b.count - a.count);
},
async fetchSuggestions() {
const currentWord = getCurrentWordFromCursor(this.search, this.cursor);
if (!currentWord)
return;
if (currentWord === this.currentWord) {
/* Show previous items, if any. */
this.open = true;
return;
}
this.currentWord = currentWord;
const params = new URLSearchParams({q: currentWord});
const response = await fetch(`${endpoints.search}?${params}`);
if (!response.ok) {
this.items = [];
return;
}
this.activeItem = null;
this.items = await response.json();
this.open = true;
},
async fetchSuggestionsOnInput(evt) {
this.cursor = evt.target.selectionStart;
await this.fetchSuggestions();
},
autocompleteSuggestion() {
if (this.items.length === 0)
return;
const pos = Math.max(this.cursor - this.currentWord.length, 0);
const tag = this.items[this.activeItem ?? 0].display;
this.items = [];
this.activeItem = null;
this.search = mySplice(this.search, pos, this.currentWord.length,
tag + ' ');
this.cursor =
this.$refs.search.selectionStart =
this.$refs.search.selectionEnd =
pos + tag.length + 1;
this.currentWord = '';
this.open = false;
this.$refs.search.focus();
},
autocompleteItem(evt) {
if (this.currentWord !== '') {
this.autocompleteSuggestion();
evt.preventDefault();
}
},
getListItemIndexOf(el) {
return [...this.$refs.suggestions.querySelectorAll('li')].indexOf(el);
},
autocompletePointedItem(evt) {
this.activeItem = this.getListItemIndexOf(evt.currentTarget);
this.autocompleteSuggestion();
},
setHoveredItem(evt) {
this.activeItem = this.getListItemIndexOf(evt.currentTarget);
},
moveActiveItem(evt, amount, defaultValue) {
const len = this.items.length;
if (len === 0)
returrn;
let item = this.activeItem === null ?
defaultValue : (this.activeItem + amount) % len;
if (item < 0)
item += len;
this.activeItem = item;
},
async moveActiveItemBackward(evt) {
await this.fetchSuggestionsOnInput(evt);
this.moveActiveItem(evt, -1, -1);
},
async moveActiveItemForward(evt) {
await this.fetchSuggestionsOnInput(evt);
this.moveActiveItem(evt, 1, 0);
},
}));
});