diff --git a/public/js/autosuggest.js b/public/js/autosuggest.js
index 066ea1b..76ab820 100644
--- a/public/js/autosuggest.js
+++ b/public/js/autosuggest.js
@@ -13,164 +13,165 @@ provided that the following conditions are met:
'use strict';
-function AutoSuggest(opt) {
- if (typeof opt.inputElement === "undefined" || typeof opt.listElement === "undefined" || typeof opt.baseUrl === "undefined" || typeof opt.appendCallback === "undefined") {
- return;
+class AutoSuggest {
+ constructor(opt) {
+ 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);
- this.input.autocomplete = "off";
- this.list = document.getElementById(opt.listElement);
- this.appendCallback = opt.appendCallback;
- this.baseurl = opt.baseUrl;
+ doSelection(event) {
+ if (typeof this.container === "undefined" || this.container.children.length === 0) {
+ return;
+ }
- var self = this;
- this.input.addEventListener('keydown', function(event) {
- self.doSelection(event);
- }, false);
- this.input.addEventListener('keyup', function(event) {
- self.onType(this, event);
- }, false);
+ switch (event.key) {
+ case 'Enter':
+ event.preventDefault();
+ this.container.children[this.selectedIndex].click();
+ break;
+
+ 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) => '' + match + ''));
+ });
+ return item;
+ };
}
-AutoSuggest.prototype.doSelection = function(event) {
- if (typeof this.container === "undefined" || this.container.children.length === 0) {
- return;
+class TagAutoSuggest extends AutoSuggest {
+ constructor(opt) {
+ super(opt);
+ this.type = "tags";
}
- switch (event.keyCode) {
- case 13: // Enter
- event.preventDefault();
- this.container.children[this.selectedIndex].click();
- break;
+ fillContainer(response) {
+ if (response.items.length > 0) {
+ super.fillContainer.call(this, response);
+ } else {
+ let node = document.createElement('li')
+ node.innerHTML = "Tag does not exist yet. Create it?";
- case 38: // Arrow up
- case 40: // Arrow down
- event.preventDefault();
- this.findSelectedElement().className = '';
- 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;
- }
-};
+ node.addEventListener('click', event => {
+ this.createNewTag(response => this.appendCallback(response));
+ this.closeContainer();
+ this.clearInput();
+ });
-AutoSuggest.prototype.findSelectedElement = function() {
- return this.container.children[this.selectedIndex];
-};
-
-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) {
+ this.container.appendChild(node);
+ this.selectedIndex = 0;
node.className = 'selected';
}
- });
-};
+ };
-
-function TagAutoSuggest(opt) {
- AutoSuggest.prototype.constructor.call(this, opt);
- 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 = "Tag does not exist yet. Create it?";
-
- 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';
+ createNewTag(callback) {
+ let request_uri = this.baseurl + '/suggest/?type=createtag';
+ let request = new HttpRequest('post', request_uri, 'tag=' + encodeURIComponent(this.input.value), callback, this);
}
-};
-
-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);
}