Modernise autosuggest code #25
@ -13,164 +13,165 @@ 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) {
|
||||||
return;
|
if (typeof opt.inputElement === "undefined" || typeof opt.listElement === "undefined" ||
|
||||||
|
typeof opt.baseUrl === "undefined" || typeof opt.appendCallback === "undefined") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.input = document.getElementById(opt.inputElement);
|
||||||
|
this.input.autocomplete = "off";
|
||||||
|
this.list = document.getElementById(opt.listElement);
|
||||||
|
this.appendCallback = opt.appendCallback;
|
||||||
|
this.baseurl = opt.baseUrl;
|
||||||
|
|
||||||
|
this.input.addEventListener('keydown', event => this.doSelection(event), false);
|
||||||
|
this.input.addEventListener('keyup', event => this.onType(event), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.input = document.getElementById(opt.inputElement);
|
doSelection(event) {
|
||||||
this.input.autocomplete = "off";
|
if (typeof this.container === "undefined" || this.container.children.length === 0) {
|
||||||
this.list = document.getElementById(opt.listElement);
|
return;
|
||||||
this.appendCallback = opt.appendCallback;
|
}
|
||||||
this.baseurl = opt.baseUrl;
|
|
||||||
|
|
||||||
var self = this;
|
switch (event.key) {
|
||||||
this.input.addEventListener('keydown', function(event) {
|
case 'Enter':
|
||||||
self.doSelection(event);
|
event.preventDefault();
|
||||||
}, false);
|
this.container.children[this.selectedIndex].click();
|
||||||
this.input.addEventListener('keyup', function(event) {
|
break;
|
||||||
self.onType(this, event);
|
|
||||||
}, false);
|
case 'ArrowUp':
|
||||||
|
case 'ArrowDown':
|
||||||
|
event.preventDefault();
|
||||||
|
this.findSelectedElement().className = '';
|
||||||
|
this.selectedIndex += event.key === 'ArrowUp' ? -1 : 1;
|
||||||
|
if (this.selectedIndex < 0) {
|
||||||
|
this.selectedIndex = this.container.children.length - 1;
|
||||||
|
} else if (this.selectedIndex === this.container.children.length) {
|
||||||
|
this.selectedIndex = 0;
|
||||||
|
}
|
||||||
|
let new_el = this.findSelectedElement().className = 'selected';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
findSelectedElement() {
|
||||||
|
return this.container.children[this.selectedIndex];
|
||||||
|
};
|
||||||
|
|
||||||
|
onType(event) {
|
||||||
|
if (['Enter', 'ArrowDown', 'ArrowUp'].indexOf(event.key) !== -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let tokens = event.target.value.split(/\s+/).filter(token => token.length >= 2);
|
||||||
|
|
||||||
|
if (tokens.length === 0) {
|
||||||
|
if (typeof this.container !== "undefined") {
|
||||||
|
this.clearContainer();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let request_uri = this.baseurl + '/suggest/?type=tags&data=' + window.encodeURIComponent(tokens.join(" "));
|
||||||
|
let request = new HttpRequest('get', request_uri, {}, this.onReceive, this);
|
||||||
|
};
|
||||||
|
|
||||||
|
onReceive(response, self) {
|
||||||
|
self.openContainer();
|
||||||
|
self.clearContainer();
|
||||||
|
self.fillContainer(response);
|
||||||
|
};
|
||||||
|
|
||||||
|
openContainer() {
|
||||||
|
if (this.container) {
|
||||||
|
if (!this.container.parentNode) {
|
||||||
|
this.input.parentNode.appendChild(this.container);
|
||||||
|
}
|
||||||
|
return this.container;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.container = document.createElement('ul');
|
||||||
|
this.container.className = 'autosuggest';
|
||||||
|
this.input.parentNode.appendChild(this.container);
|
||||||
|
return this.container;
|
||||||
|
};
|
||||||
|
|
||||||
|
clearContainer() {
|
||||||
|
while (this.container.children.length > 0) {
|
||||||
|
this.container.removeChild(this.container.children[0]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
clearInput() {
|
||||||
|
this.input.value = "";
|
||||||
|
this.input.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
closeContainer() {
|
||||||
|
this.container.parentNode.removeChild(this.container);
|
||||||
|
};
|
||||||
|
|
||||||
|
fillContainer(response) {
|
||||||
|
this.selectedIndex = 0;
|
||||||
|
|
||||||
|
let query = this.input.value.trim().replace(/[\-\[\]{}()*+?.,\\\/^\$|#]/g, ' ');
|
||||||
|
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.addEventListener('click', event => {
|
||||||
|
this.appendCallback(event.target.jsondata);
|
||||||
|
this.closeContainer();
|
||||||
|
this.clearInput();
|
||||||
|
});
|
||||||
|
this.container.appendChild(node);
|
||||||
|
if (this.container.children.length === 1) {
|
||||||
|
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;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
AutoSuggest.prototype.doSelection = function(event) {
|
class TagAutoSuggest extends AutoSuggest {
|
||||||
if (typeof this.container === "undefined" || this.container.children.length === 0) {
|
constructor(opt) {
|
||||||
return;
|
super(opt);
|
||||||
|
this.type = "tags";
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (event.keyCode) {
|
fillContainer(response) {
|
||||||
case 13: // Enter
|
if (response.items.length > 0) {
|
||||||
event.preventDefault();
|
super.fillContainer.call(this, response);
|
||||||
this.container.children[this.selectedIndex].click();
|
} else {
|
||||||
break;
|
let node = document.createElement('li')
|
||||||
|
node.innerHTML = "<em>Tag does not exist yet. Create it?</em>";
|
||||||
|
|
||||||
case 38: // Arrow up
|
node.addEventListener('click', event => {
|
||||||
case 40: // Arrow down
|
this.createNewTag(response => this.appendCallback(response));
|
||||||
event.preventDefault();
|
this.closeContainer();
|
||||||
this.findSelectedElement().className = '';
|
this.clearInput();
|
||||||
this.selectedIndex += event.keyCode === 38 ? -1 : 1;
|
});
|
||||||
if (this.selectedIndex < 0) {
|
|
||||||
this.selectedIndex = this.container.children.length - 1;
|
|
||||||
} else if (this.selectedIndex === this.container.children.length) {
|
|
||||||
this.selectedIndex = 0;
|
|
||||||
}
|
|
||||||
var new_el = this.findSelectedElement().className = 'selected';
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoSuggest.prototype.findSelectedElement = function() {
|
this.container.appendChild(node);
|
||||||
return this.container.children[this.selectedIndex];
|
this.selectedIndex = 0;
|
||||||
};
|
|
||||||
|
|
||||||
AutoSuggest.prototype.onType = function(input, event) {
|
|
||||||
if (event.keyCode === 13 || event.keyCode === 38 || event.keyCode === 40) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var tokens = input.value.split(/\s+/).filter(function(token) {
|
|
||||||
return token.length >= 2;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (tokens.length === 0) {
|
|
||||||
if (typeof this.container !== "undefined") {
|
|
||||||
this.clearContainer();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var request_uri = this.baseurl + '/suggest/?type=tags&data=' + window.encodeURIComponent(tokens.join(" "));
|
|
||||||
var request = new HttpRequest('get', request_uri, {}, this.onReceive, this);
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoSuggest.prototype.onReceive = function(response, self) {
|
|
||||||
self.openContainer();
|
|
||||||
self.clearContainer();
|
|
||||||
self.fillContainer(response);
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoSuggest.prototype.openContainer = function() {
|
|
||||||
if (this.container) {
|
|
||||||
if (!this.container.parentNode) {
|
|
||||||
this.input.parentNode.appendChild(this.container);
|
|
||||||
}
|
|
||||||
return this.container;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.container = document.createElement('ul');
|
|
||||||
this.container.className = 'autosuggest';
|
|
||||||
this.input.parentNode.appendChild(this.container);
|
|
||||||
return this.container;
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoSuggest.prototype.clearContainer = function() {
|
|
||||||
while (this.container.children.length > 0) {
|
|
||||||
this.container.removeChild(this.container.children[0]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoSuggest.prototype.clearInput = function() {
|
|
||||||
this.input.value = "";
|
|
||||||
this.input.focus();
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoSuggest.prototype.closeContainer = function() {
|
|
||||||
this.container.parentNode.removeChild(this.container);
|
|
||||||
};
|
|
||||||
|
|
||||||
AutoSuggest.prototype.fillContainer = function(response) {
|
|
||||||
var self = this;
|
|
||||||
this.selectedIndex = 0;
|
|
||||||
response.items.forEach(function(item, i) {
|
|
||||||
var node = document.createElement('li');
|
|
||||||
var text = document.createTextNode(item.label);
|
|
||||||
node.jsondata = item;
|
|
||||||
node.addEventListener('click', function(event) {
|
|
||||||
self.appendCallback(this.jsondata);
|
|
||||||
self.closeContainer();
|
|
||||||
self.clearInput();
|
|
||||||
});
|
|
||||||
node.appendChild(text);
|
|
||||||
self.container.appendChild(node);
|
|
||||||
if (self.container.children.length === 1) {
|
|
||||||
node.className = 'selected';
|
node.className = 'selected';
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
};
|
|
||||||
|
|
||||||
|
createNewTag(callback) {
|
||||||
function TagAutoSuggest(opt) {
|
let request_uri = this.baseurl + '/suggest/?type=createtag';
|
||||||
AutoSuggest.prototype.constructor.call(this, opt);
|
let request = new HttpRequest('post', request_uri, 'tag=' + encodeURIComponent(this.input.value), callback, this);
|
||||||
this.type = "tags";
|
|
||||||
}
|
|
||||||
|
|
||||||
TagAutoSuggest.prototype = Object.create(AutoSuggest.prototype);
|
|
||||||
|
|
||||||
TagAutoSuggest.prototype.constructor = TagAutoSuggest;
|
|
||||||
|
|
||||||
TagAutoSuggest.prototype.fillContainer = function(response) {
|
|
||||||
if (response.items.length > 0) {
|
|
||||||
AutoSuggest.prototype.fillContainer.call(this, response);
|
|
||||||
} else {
|
|
||||||
var node = document.createElement('li')
|
|
||||||
node.innerHTML = "<em>Tag does not exist yet. Create it?</em>";
|
|
||||||
|
|
||||||
var self = this;
|
|
||||||
node.addEventListener('click', function(event) {
|
|
||||||
self.createNewTag(function(response) {
|
|
||||||
self.appendCallback(response);
|
|
||||||
});
|
|
||||||
self.closeContainer();
|
|
||||||
self.clearInput();
|
|
||||||
});
|
|
||||||
|
|
||||||
self.container.appendChild(node);
|
|
||||||
this.selectedIndex = 0;
|
|
||||||
node.className = 'selected';
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
TagAutoSuggest.prototype.createNewTag = function(callback) {
|
|
||||||
var request_uri = this.baseurl + '/suggest/?type=createtag';
|
|
||||||
var request = new HttpRequest('post', request_uri, 'tag=' + encodeURIComponent(this.input.value), callback, this);
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user