site: decouple state from event handlers
Try to avoid directly setting state from event handlers and instead provide utility functions that mutate state in a consistent way.
This commit is contained in:
parent
b1cd0dad8d
commit
8168bb9715
2 changed files with 42 additions and 29 deletions
|
@ -6,7 +6,7 @@ function mySplice(s, idx, del, n) {
|
|||
return s.substring(0, idx) + n + s.substring(idx + del);
|
||||
}
|
||||
|
||||
function suggestionPosition(el) {
|
||||
function suggestionIndex(el) {
|
||||
// el.parentNode is ul#tags-suggestion, which include a template. That's why
|
||||
// a -1 is needed here.
|
||||
const idx = [...el.parentNode.children].indexOf(el);
|
||||
|
@ -52,50 +52,63 @@ document.addEventListener('alpine:init', () => {
|
|||
this.suggestions = await response.json();
|
||||
},
|
||||
|
||||
completeSuggestion(evt) {
|
||||
completeSuggestion() {
|
||||
if (this.currentSuggestion === null)
|
||||
return;
|
||||
|
||||
const value = this.$refs.tags.value;
|
||||
const pos = this.inputCursor - this.query.length;
|
||||
const pos = Math.max(this.inputCursor - this.query.length, 0);
|
||||
const tag = this.suggestions[this.currentSuggestion].display;
|
||||
const newValue = mySplice(value, pos, this.query.length, tag + ' ');
|
||||
|
||||
this.$refs.tags.value = mySplice(value, pos, this.query.length,
|
||||
tag + ' ');
|
||||
this.reset();
|
||||
|
||||
this.$refs.tags.value = newValue;
|
||||
this.inputCursor =
|
||||
this.$refs.tags.selectionStart =
|
||||
this.$refs.tags.selectionEnd =
|
||||
pos + tag.length + 1;
|
||||
|
||||
this.$refs.tags.focus();
|
||||
|
||||
// Don't switch focus if we're completing after a Tab press.
|
||||
if (evt.type === "keydown" && evt.keyCode === 9)
|
||||
evt.preventDefault();
|
||||
},
|
||||
|
||||
selectCurrentSuggestion(evt) {
|
||||
this.currentSuggestion = suggestionPosition(evt.currentTarget);
|
||||
this.completeSuggestion(evt);
|
||||
completeClickedSuggestion(evt) {
|
||||
this.currentSuggestion = suggestionIndex(evt.currentTarget);
|
||||
this.completeSuggestion();
|
||||
},
|
||||
|
||||
setCurrentSuggestion(evt, amount = 0) {
|
||||
setCurrentSuggestion(idx) {
|
||||
const len = this.suggestions.length;
|
||||
if (len === 0)
|
||||
return;
|
||||
|
||||
currentSuggestionElement(this.currentSuggestion)
|
||||
?.classList.remove("suggestion-hover");
|
||||
|
||||
if (evt.type === 'mouseenter')
|
||||
this.currentSuggestion = suggestionPosition(evt.currentTarget);
|
||||
else {
|
||||
const len = this.suggestions.length;
|
||||
let cur = this.currentSuggestion;
|
||||
|
||||
if (cur === null)
|
||||
cur = amount > 0 ? -1 : amount < 0 ? len : 0;
|
||||
this.currentSuggestion = (cur + amount + len) % len;
|
||||
}
|
||||
idx = idx % len;
|
||||
if (idx < 0)
|
||||
idx += len;
|
||||
this.currentSuggestion = idx;
|
||||
|
||||
currentSuggestionElement(this.currentSuggestion)
|
||||
?.classList.add("suggestion-hover");
|
||||
}
|
||||
},
|
||||
|
||||
setPointerSuggestion(evt) {
|
||||
this.setCurrentSuggestion(suggestionIndex(evt.currentTarget));
|
||||
},
|
||||
|
||||
moveCurrentSuggestion(amount, defaultValue) {
|
||||
this.setCurrentSuggestion(this.currentSuggestion === null ?
|
||||
defaultValue : this.currentSuggestion + amount);
|
||||
},
|
||||
|
||||
nextSuggestion(evt) {
|
||||
this.moveCurrentSuggestion(1, 0);
|
||||
},
|
||||
|
||||
previousSuggestion(evt) {
|
||||
this.moveCurrentSuggestion(-1, -1);
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue