forked from mirrors/bookwyrm
Merge pull request #1699 from bookwyrm-social/autocomplete
Autocomplete script
This commit is contained in:
commit
7bb634b71f
4 changed files with 184 additions and 1 deletions
164
bookwyrm/static/js/autocomplete.js
Normal file
164
bookwyrm/static/js/autocomplete.js
Normal file
|
@ -0,0 +1,164 @@
|
|||
(function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Suggest a completion as a user types
|
||||
*
|
||||
* Use `data-autocomplete="<completions set identifier>"`on the input field.
|
||||
* specifying the trie to be used for autocomplete
|
||||
*
|
||||
* @example
|
||||
* <input
|
||||
* type="input"
|
||||
* data-autocomplete="mimetype"
|
||||
* >
|
||||
* @param {Event} event
|
||||
* @return {undefined}
|
||||
*/
|
||||
function autocomplete(event) {
|
||||
const input = event.target;
|
||||
|
||||
// Get suggestions
|
||||
let trie = tries[input.getAttribute("data-autocomplete")];
|
||||
|
||||
let suggestions = getSuggestions(input.value, trie);
|
||||
|
||||
const boxId = input.getAttribute("list");
|
||||
|
||||
// Create suggestion box, if needed
|
||||
let suggestionsBox = document.getElementById(boxId);
|
||||
|
||||
// Clear existing suggestions
|
||||
suggestionsBox.innerHTML = "";
|
||||
|
||||
// Populate suggestions box
|
||||
suggestions.forEach((suggestion) => {
|
||||
const suggestionItem = document.createElement("option");
|
||||
|
||||
suggestionItem.textContent = suggestion;
|
||||
suggestionsBox.appendChild(suggestionItem);
|
||||
});
|
||||
}
|
||||
|
||||
function getSuggestions(input, trie) {
|
||||
// Follow the trie through the provided input
|
||||
input.split("").forEach((letter) => {
|
||||
if (!trie) {
|
||||
return;
|
||||
}
|
||||
|
||||
trie = trie[letter];
|
||||
});
|
||||
|
||||
if (!trie) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return searchTrie(trie);
|
||||
}
|
||||
|
||||
function searchTrie(trie) {
|
||||
const options = Object.values(trie);
|
||||
|
||||
if (typeof trie == "string") {
|
||||
return [trie];
|
||||
}
|
||||
|
||||
return options
|
||||
.map((option) => {
|
||||
const newTrie = option;
|
||||
|
||||
if (typeof newTrie == "string") {
|
||||
return [newTrie];
|
||||
}
|
||||
|
||||
return searchTrie(newTrie);
|
||||
})
|
||||
.reduce((prev, next) => prev.concat(next));
|
||||
}
|
||||
|
||||
document.querySelectorAll("[data-autocomplete]").forEach((input) => {
|
||||
input.addEventListener("input", autocomplete);
|
||||
});
|
||||
})();
|
||||
|
||||
const tries = {"mimetype": {
|
||||
a: {
|
||||
a: {
|
||||
c: "AAC",
|
||||
},
|
||||
z: {
|
||||
w: "AZW",
|
||||
},
|
||||
},
|
||||
d: {
|
||||
a: {
|
||||
i: {
|
||||
s: {
|
||||
y: "Daisy",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
e: {
|
||||
p: {
|
||||
u: {
|
||||
b: "ePub",
|
||||
},
|
||||
},
|
||||
},
|
||||
f: {
|
||||
l: {
|
||||
a: {
|
||||
c: "FLAC",
|
||||
},
|
||||
},
|
||||
},
|
||||
h: {
|
||||
t: {
|
||||
m: {
|
||||
l: "HTML",
|
||||
},
|
||||
},
|
||||
},
|
||||
m: {
|
||||
4: {
|
||||
a: "M4A",
|
||||
b: "M4B",
|
||||
},
|
||||
o: {
|
||||
b: {
|
||||
i: "MOBI",
|
||||
},
|
||||
},
|
||||
p: {
|
||||
3: "MP3",
|
||||
},
|
||||
},
|
||||
o: {
|
||||
g: {
|
||||
g: "OGG",
|
||||
},
|
||||
},
|
||||
p: {
|
||||
d: {
|
||||
f: "PDF",
|
||||
},
|
||||
l: {
|
||||
a: {
|
||||
i: {
|
||||
n: {
|
||||
t: {
|
||||
e: {
|
||||
x: {
|
||||
t: "Plaintext",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
|
@ -386,4 +386,5 @@
|
|||
|
||||
{% block scripts %}
|
||||
<script src="{% static "js/vendor/tabs.js" %}?v={{ js_cache }}"></script>
|
||||
<script src="{% static "js/autocomplete.js" %}?v={{ js_cache }}"></script>
|
||||
{% endblock %}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{% extends 'components/modal.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% block modal-title %}
|
||||
{% trans "Add file link" %}
|
||||
|
@ -26,7 +27,19 @@
|
|||
</div>
|
||||
<div class="column is-one-fifth">
|
||||
<label class="label" for="id_filetype">{% trans "File type:" %}</label>
|
||||
<input type="text" name="filetype" maxlength="5" class="input" required="" id="id_filetype" value="{% firstof file_link_form.filetype.value "" %}" placeholder="PDF">
|
||||
<input
|
||||
type="text"
|
||||
name="filetype"
|
||||
maxlength="5"
|
||||
class="input"
|
||||
required=""
|
||||
id="id_filetype"
|
||||
value="{% firstof file_link_form.filetype.value '' %}"
|
||||
placeholder="ePub"
|
||||
list="mimetypes-list"
|
||||
data-autocomplete="mimetype"
|
||||
>
|
||||
<datalist id="mimetypes-list"></datalist>
|
||||
{% include 'snippets/form_errors.html' with errors_list=file_link_form.filetype.errors id="desc_filetype" %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{% extends 'layout.html' %}
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}
|
||||
{% trans "File Links" %}
|
||||
|
@ -8,3 +9,7 @@
|
|||
{% block content %}
|
||||
{% include "book/file_links/add_link_modal.html" with book=book active=True static=True id="file-link" %}
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
<script src="{% static "js/autocomplete.js" %}?v={{ js_cache }}"></script>
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue