mirror of
https://github.com/chinchang/web-maker.git
synced 2025-10-10 19:14:33 +02:00
141 lines
4.6 KiB
JavaScript
141 lines
4.6 KiB
JavaScript
// textarea-autocomplete.js
|
|
(function() {
|
|
|
|
class TextareaAutoComplete {
|
|
|
|
constructor (textarea, filter) {
|
|
this.t = textarea;
|
|
this.filter = filter;
|
|
var wrap = document.createElement('div');
|
|
wrap.classList.add('btn-group');
|
|
textarea.parentElement.insertBefore(wrap, textarea);
|
|
wrap.insertBefore(textarea, null);
|
|
this.list = document.createElement('ul');
|
|
this.list.classList.add('dropdown__menu');
|
|
this.list.classList.add('autocomplete-dropdown');
|
|
wrap.insertBefore(this.list, null);
|
|
|
|
this.loader = document.createElement('div');
|
|
this.loader.classList.add('loader');
|
|
this.loader.classList.add('autocomplete__loader');
|
|
this.loader.style.display = 'none';
|
|
wrap.insertBefore(this.loader, null);
|
|
|
|
// after list is insrted into the DOM, we put it in the body
|
|
// fixed at same position
|
|
setTimeout(() => {
|
|
requestIdleCallback(() => {
|
|
document.body.appendChild(this.list);
|
|
this.list.style.position = 'fixed';
|
|
});
|
|
},100);
|
|
|
|
this.t.addEventListener('input', (e) => this.onInput(e));
|
|
this.t.addEventListener('keydown', (e) => this.onKeyDown(e));
|
|
this.t.addEventListener('blur', (e) => this.closeSuggestions(e));
|
|
this.list.addEventListener('mousedown', (e) => this.onListMouseDown(e));
|
|
}
|
|
|
|
get currentLineNumber() {
|
|
return this.t.value.substr(0, this.t.selectionStart).split('\n').length;
|
|
}
|
|
get currentLine() {
|
|
var line = this.currentLineNumber;
|
|
return this.t.value.split('\n')[line - 1];
|
|
}
|
|
closeSuggestions() {
|
|
this.list.classList.remove('is-open');
|
|
this.isShowingSuggestions = false;
|
|
}
|
|
getList(input) {
|
|
var url = 'https://api.cdnjs.com/libraries?search=';
|
|
return fetch(url + input)
|
|
.then((response) => {
|
|
return response.json().then((json) => json.results);
|
|
});
|
|
}
|
|
replaceCurrentLine(val) {
|
|
var lines = this.t.value.split('\n');
|
|
lines.splice(this.currentLineNumber - 1, 1, val)
|
|
this.t.value = lines.join('\n');
|
|
}
|
|
onInput() {
|
|
var currentLine = this.currentLine;
|
|
if (currentLine) {
|
|
if (currentLine.indexOf('/') !== -1 || currentLine.match(/https*:\/\//)) { return; }
|
|
clearTimeout(this.timeout);
|
|
this.timeout = setTimeout(() => {
|
|
this.loader.style.display = 'block';
|
|
this.getList(currentLine).then((arr) => {
|
|
this.loader.style.display = 'none';
|
|
if (!arr.length) {
|
|
this.closeSuggestions();
|
|
return;
|
|
}
|
|
this.list.innerHTML = '';
|
|
if (this.filter) {
|
|
|
|
/* eslint-disable no-param-reassign */
|
|
arr = arr.filter(this.filter);
|
|
}
|
|
for (var i = 0; i < Math.min(arr.length, 10); i++) {
|
|
this.list.innerHTML += `<li data-url="${arr[i].latest}"><a>${arr[i].name}</a></li>`;
|
|
}
|
|
this.isShowingSuggestions = true;
|
|
if (!this.textareaBounds) {
|
|
this.textareaBounds = this.t.getBoundingClientRect();
|
|
this.list.style.top = this.textareaBounds.bottom + 'px';
|
|
this.list.style.left = this.textareaBounds.left + 'px';
|
|
this.list.style.width = this.textareaBounds.width + 'px';
|
|
}
|
|
this.list.classList.add('is-open');
|
|
});
|
|
}, 500);
|
|
}
|
|
}
|
|
onKeyDown(event) {
|
|
var selectedItemElement;
|
|
if (!this.isShowingSuggestions) { return; }
|
|
|
|
if (event.keyCode === 27) {
|
|
this.closeSuggestions();
|
|
event.stopPropagation();
|
|
}
|
|
if (event.keyCode === 40 && this.isShowingSuggestions) {
|
|
selectedItemElement = this.list.querySelector('.selected');
|
|
if (selectedItemElement) {
|
|
selectedItemElement.classList.remove('selected');
|
|
selectedItemElement.nextElementSibling.classList.add('selected');
|
|
} else {
|
|
this.list.querySelector('li:first-child').classList.add('selected');
|
|
}
|
|
this.list.querySelector('.selected').scrollIntoView(false);
|
|
event.preventDefault();
|
|
} else if (event.keyCode === 38 && this.isShowingSuggestions) {
|
|
selectedItemElement = this.list.querySelector('.selected');
|
|
if (selectedItemElement) {
|
|
selectedItemElement.classList.remove('selected');
|
|
selectedItemElement.previousElementSibling.classList.add('selected');
|
|
} else {
|
|
this.list.querySelector('li:first-child').classList.add('selected');
|
|
}
|
|
this.list.querySelector('.selected').scrollIntoView(false);
|
|
event.preventDefault();
|
|
} else if (event.keyCode === 13 && this.isShowingSuggestions) {
|
|
selectedItemElement = this.list.querySelector('.selected');
|
|
this.replaceCurrentLine(selectedItemElement.dataset.url)
|
|
this.closeSuggestions();
|
|
}
|
|
}
|
|
onListMouseDown(event) {
|
|
var target = event.target;
|
|
if (target.parentElement.dataset.url) {
|
|
this.replaceCurrentLine(target.parentElement.dataset.url)
|
|
this.closeSuggestions();
|
|
}
|
|
}
|
|
}
|
|
|
|
window.TextareaAutoComplete = TextareaAutoComplete;
|
|
|
|
})(); |