// retoor <retoor@molodetz.nl>
import { Http } from "./Http.js";
import { Avatar } from "./Avatar.js";
import { TextInput } from "./TextInput.js";
import { DomUtils } from "./DomUtils.js";
import { ListNav } from "./ListNav.js";
export class MentionInput {
constructor(element) {
this.input = element;
this.dropdown = null;
this.debounceTimer = null;
this.lastMatch = null;
this.nav = null;
this.build();
}
build() {
const wrap = document.createElement("div");
wrap.className = "mention-wrapper";
this.input.parentNode.insertBefore(wrap, this.input);
wrap.appendChild(this.input);
this.dropdown = document.createElement("div");
this.dropdown.className = "mention-dropdown";
this.dropdown.setAttribute("role", "listbox");
wrap.appendChild(this.dropdown);
this.nav = new ListNav(this.input, this.dropdown, {
itemSelector: ".mention-dropdown-item",
activeClass: "active",
isOpen: () => DomUtils.isShown(this.dropdown),
onChoose: (item) => this.insert(item.dataset.username),
onEscape: () => this.hide(),
});
this.input.addEventListener("input", () => this.onInput());
this.input.addEventListener("blur", () => {
setTimeout(() => this.hide(), 200);
});
}
hide() {
DomUtils.hide(this.dropdown);
this.nav.closed();
}
onInput() {
clearTimeout(this.debounceTimer);
const pos = this.input.selectionStart;
const text = this.input.value.substring(0, pos);
let match = text.match(/(?:^|\s|\x28)@([a-zA-Z0-9_-]*)$/);
if (!match) {
this.hide();
this.lastMatch = null;
return;
}
const query = match[1];
this.lastMatch = { query, index: match.index + (text[match.index] === "@" ? 0 : 1) };
if (query.length < 1) {
this.hide();
return;
}
this.debounceTimer = setTimeout(() => this.fetch(query), 200);
}
async fetch(query) {
try {
const data = await Http.getJson("/profile/search?q=" + encodeURIComponent(query));
const results = data.results || [];
if (results.length === 0) {
this.hide();
return;
}
this.render(results);
} catch (e) {
this.hide();
}
}
render(results) {
this.dropdown.innerHTML = "";
for (const r of results) {
const item = document.createElement("button");
item.type = "button";
item.className = "mention-dropdown-item";
item.dataset.username = r.username;
const label = document.createElement("span");
label.textContent = "@" + r.username;
item.append(Avatar.imgElement(r.username), label);
item.addEventListener("mousedown", (e) => {
e.preventDefault();
this.insert(r.username);
});
this.dropdown.appendChild(item);
}
DomUtils.show(this.dropdown);
this.nav.opened();
}
insert(username) {
if (!this.lastMatch) return;
const val = this.input.value;
let before = val.substring(0, this.lastMatch.index);
let after = val.substring(this.lastMatch.index + this.lastMatch.query.length + 1);
before = before.replace(/@+$/, "");
after = after.replace(/^@+/, "");
TextInput.applyValue(this.input, before + "@" + username + " " + after, before.length + username.length + 2);
this.hide();
this.lastMatch = null;
}
}
window.MentionInput = MentionInput;