Implement autocomplete and smart queries

This commit is contained in:
Zaid Abdulla committed 2018-12-26 00:22:07 -08:00
1 parent 518254aa55
commit 5b84b1daad
10 files changed
+331 -47

No files matched your search

+113
View File
@@ -0,0 +1,113 @@
"use strict";
class Autocomplete {
constructor(className, callback) {
this.callback = callback;
this.element = null;
this.hideTimeout = null;
this.visible = false;
this.default = null;
this.container = document.createElement("div");
this.container.style.position = "absolute";
this.container.style.display = "block";
this.container.style.opacity = 0;
this.container.className = className;
}
attach(el) {
el.setAttribute("autocomplete", "off");
el.addEventListener("focus", () => {
this.element = el;
let domRect = el.getBoundingClientRect();
this.container.style.left = `${domRect.left}px`;
this.container.style.width = `${domRect.width}px`;
this.container.style.top = `${domRect.bottom}px`;
this.update();
});
el.addEventListener("blur", () => {
if (this.element !== el) return;
if (!this.visible) return;
this.default = null;
this.hide();
});
el.addEventListener("keydown", e => {
if (this.element !== el) return;
if (e.key === "Escape") this.hide();
else if (e.key === "Enter")
if (this.default != null) {
el.value = this.default;
e.preventDefault();
this.update();
}
});
el.addEventListener("input", () => {
if (this.element !== el) return;
this.update();
});
}
hide() {
this.container.style.opacity = 0;
this.visible = false;
this.default = null;
clearTimeout(this.hideTimeout);
this.hideTimeout = setTimeout(() => {
this.hideTimeout = null;
while (this.container.firstChild)
this.container.removeChild(this.container.firstChild);
document.body.removeChild(this.container);
}, 500);
}
update() {
const el = this.element;
this.callback(el.value, suggestions => {
if (this.element !== el) return;
this.default = null;
if (!suggestions.length) {
if (this.visible) this.hide();
return;
}
while (this.container.firstChild)
this.container.removeChild(this.container.firstChild);
if (!this.visible) {
if (!this.hideTimeout) {
document.body.appendChild(this.container);
window.getComputedStyle(this.container).opacity;
} else {
clearTimeout(this.hideTimeout);
this.hideTimeout = null;
}
this.container.style.opacity = 1;
this.visible = true;
}
this.default = suggestions[0];
for (let suggestion of suggestions) {
let e = document.createElement("div");
e.className = "suggestion";
let t = document.createTextNode(suggestion);
e.appendChild(t);
e.addEventListener("mousedown", ev => {
ev.preventDefault();
el.value = suggestion;
if (this.element === el) this.update(el);
});
this.container.appendChild(e);
}
});
}
}
export default Autocomplete;