Modernise autosuggest code #25

Merged
Roflin merged 3 commits from autosuggest into master 2021-05-17 20:19:07 +02:00

View File

@ -13,8 +13,10 @@ provided that the following conditions are met:
'use strict'; 'use strict';
function AutoSuggest(opt) { class AutoSuggest {
if (typeof opt.inputElement === "undefined" || typeof opt.listElement === "undefined" || typeof opt.baseUrl === "undefined" || typeof opt.appendCallback === "undefined") { constructor(opt) {
if (typeof opt.inputElement === "undefined" || typeof opt.listElement === "undefined" ||
typeof opt.baseUrl === "undefined" || typeof opt.appendCallback === "undefined") {
return; return;
} }
@ -24,53 +26,46 @@ function AutoSuggest(opt) {
this.appendCallback = opt.appendCallback; this.appendCallback = opt.appendCallback;
this.baseurl = opt.baseUrl; this.baseurl = opt.baseUrl;
var self = this; this.input.addEventListener('keydown', event => this.doSelection(event), false);
this.input.addEventListener('keydown', function(event) { this.input.addEventListener('keyup', event => this.onType(event), false);
self.doSelection(event);
}, false);
this.input.addEventListener('keyup', function(event) {
self.onType(this, event);
}, false);
} }
AutoSuggest.prototype.doSelection = function(event) { doSelection(event) {
if (typeof this.container === "undefined" || this.container.children.length === 0) { if (typeof this.container === "undefined" || this.container.children.length === 0) {
return; return;
} }
switch (event.keyCode) { switch (event.key) {
case 13: // Enter case 'Enter':
event.preventDefault(); event.preventDefault();
this.container.children[this.selectedIndex].click(); this.container.children[this.selectedIndex].click();
break; break;
case 38: // Arrow up case 'ArrowUp':
case 40: // Arrow down case 'ArrowDown':
event.preventDefault(); event.preventDefault();
this.findSelectedElement().className = ''; this.findSelectedElement().className = '';
this.selectedIndex += event.keyCode === 38 ? -1 : 1; this.selectedIndex += event.key === 'ArrowUp' ? -1 : 1;
if (this.selectedIndex < 0) { if (this.selectedIndex < 0) {
this.selectedIndex = this.container.children.length - 1; this.selectedIndex = this.container.children.length - 1;
} else if (this.selectedIndex === this.container.children.length) { } else if (this.selectedIndex === this.container.children.length) {
this.selectedIndex = 0; this.selectedIndex = 0;
} }
var new_el = this.findSelectedElement().className = 'selected'; let new_el = this.findSelectedElement().className = 'selected';
break; break;
} }
}; };
AutoSuggest.prototype.findSelectedElement = function() { findSelectedElement() {
return this.container.children[this.selectedIndex]; return this.container.children[this.selectedIndex];
}; };
AutoSuggest.prototype.onType = function(input, event) { onType(event) {
if (event.keyCode === 13 || event.keyCode === 38 || event.keyCode === 40) { if (['Enter', 'ArrowDown', 'ArrowUp'].indexOf(event.key) !== -1) {
return; return;
} }
var tokens = input.value.split(/\s+/).filter(function(token) { let tokens = event.target.value.split(/\s+/).filter(token => token.length >= 2);
return token.length >= 2;
});
if (tokens.length === 0) { if (tokens.length === 0) {
if (typeof this.container !== "undefined") { if (typeof this.container !== "undefined") {
@ -79,17 +74,17 @@ AutoSuggest.prototype.onType = function(input, event) {
return false; return false;
} }
var request_uri = this.baseurl + '/suggest/?type=tags&data=' + window.encodeURIComponent(tokens.join(" ")); let request_uri = this.baseurl + '/suggest/?type=tags&data=' + window.encodeURIComponent(tokens.join(" "));
var request = new HttpRequest('get', request_uri, {}, this.onReceive, this); let request = new HttpRequest('get', request_uri, {}, this.onReceive, this);
}; };
AutoSuggest.prototype.onReceive = function(response, self) { onReceive(response, self) {
self.openContainer(); self.openContainer();
self.clearContainer(); self.clearContainer();
self.fillContainer(response); self.fillContainer(response);
}; };
AutoSuggest.prototype.openContainer = function() { openContainer() {
if (this.container) { if (this.container) {
if (!this.container.parentNode) { if (!this.container.parentNode) {
this.input.parentNode.appendChild(this.container); this.input.parentNode.appendChild(this.container);
@ -103,74 +98,80 @@ AutoSuggest.prototype.openContainer = function() {
return this.container; return this.container;
}; };
AutoSuggest.prototype.clearContainer = function() { clearContainer() {
while (this.container.children.length > 0) { while (this.container.children.length > 0) {
this.container.removeChild(this.container.children[0]); this.container.removeChild(this.container.children[0]);
} }
}; };
AutoSuggest.prototype.clearInput = function() { clearInput() {
this.input.value = ""; this.input.value = "";
this.input.focus(); this.input.focus();
}; };
AutoSuggest.prototype.closeContainer = function() { closeContainer() {
this.container.parentNode.removeChild(this.container); this.container.parentNode.removeChild(this.container);
}; };
AutoSuggest.prototype.fillContainer = function(response) { fillContainer(response) {
var self = this;
this.selectedIndex = 0; this.selectedIndex = 0;
response.items.forEach(function(item, i) {
var node = document.createElement('li'); let query = this.input.value.trim().replace(/[\-\[\]{}()*+?.,\\\/^\$|#]/g, ' ');
var text = document.createTextNode(item.label); let query_tokens = query.split(/ +/).sort((a,b) => a.length - b.length);
response.items.forEach((item, i) => {
let node = document.createElement('li');
node.innerHTML = this.highlightMatches(query_tokens, item.label);
node.jsondata = item; node.jsondata = item;
node.addEventListener('click', function(event) { node.addEventListener('click', event => {
self.appendCallback(this.jsondata); this.appendCallback(event.target.jsondata);
self.closeContainer(); this.closeContainer();
self.clearInput(); this.clearInput();
}); });
node.appendChild(text); this.container.appendChild(node);
self.container.appendChild(node); if (this.container.children.length === 1) {
if (self.container.children.length === 1) {
node.className = 'selected'; node.className = 'selected';
} }
}); });
}; };
highlightMatches(query_tokens, item) {
let itemTokens = item.split(/ +/);
let queryTokens = new RegExp('(' + query_tokens.join('\|') + ')', 'i');
itemTokens.forEach((token, index) => {
item = item.replace(token, token.replace(queryTokens, ($1, match) => '<strong>' + match + '</strong>'));
});
return item;
};
}
function TagAutoSuggest(opt) { class TagAutoSuggest extends AutoSuggest {
AutoSuggest.prototype.constructor.call(this, opt); constructor(opt) {
super(opt);
this.type = "tags"; this.type = "tags";
} }
TagAutoSuggest.prototype = Object.create(AutoSuggest.prototype); fillContainer(response) {
TagAutoSuggest.prototype.constructor = TagAutoSuggest;
TagAutoSuggest.prototype.fillContainer = function(response) {
if (response.items.length > 0) { if (response.items.length > 0) {
AutoSuggest.prototype.fillContainer.call(this, response); super.fillContainer.call(this, response);
} else { } else {
var node = document.createElement('li') let node = document.createElement('li')
node.innerHTML = "<em>Tag does not exist yet. Create it?</em>"; node.innerHTML = "<em>Tag does not exist yet. Create it?</em>";
var self = this; node.addEventListener('click', event => {
node.addEventListener('click', function(event) { this.createNewTag(response => this.appendCallback(response));
self.createNewTag(function(response) { this.closeContainer();
self.appendCallback(response); this.clearInput();
});
self.closeContainer();
self.clearInput();
}); });
self.container.appendChild(node); this.container.appendChild(node);
this.selectedIndex = 0; this.selectedIndex = 0;
node.className = 'selected'; node.className = 'selected';
} }
}; };
TagAutoSuggest.prototype.createNewTag = function(callback) { createNewTag(callback) {
var request_uri = this.baseurl + '/suggest/?type=createtag'; let request_uri = this.baseurl + '/suggest/?type=createtag';
var request = new HttpRequest('post', request_uri, 'tag=' + encodeURIComponent(this.input.value), callback, this); let request = new HttpRequest('post', request_uri, 'tag=' + encodeURIComponent(this.input.value), callback, this);
}
} }