Modernise autosuggest code #25
| @ -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) => '<strong>' + match + '</strong>')); | ||||
|         }); | ||||
|         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 = "<em>Tag does not exist yet. Create it?</em>"; | ||||
| 
 | ||||
|         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 = "<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'; | ||||
|     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); | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user