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 %}
|
{% block scripts %}
|
||||||
<script src="{% static "js/vendor/tabs.js" %}?v={{ js_cache }}"></script>
|
<script src="{% static "js/vendor/tabs.js" %}?v={{ js_cache }}"></script>
|
||||||
|
<script src="{% static "js/autocomplete.js" %}?v={{ js_cache }}"></script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{% extends 'components/modal.html' %}
|
{% extends 'components/modal.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% block modal-title %}
|
{% block modal-title %}
|
||||||
{% trans "Add file link" %}
|
{% trans "Add file link" %}
|
||||||
|
@ -26,7 +27,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="column is-one-fifth">
|
<div class="column is-one-fifth">
|
||||||
<label class="label" for="id_filetype">{% trans "File type:" %}</label>
|
<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" %}
|
{% include 'snippets/form_errors.html' with errors_list=file_link_form.filetype.errors id="desc_filetype" %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
{% extends 'layout.html' %}
|
{% extends 'layout.html' %}
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
{% block title %}
|
{% block title %}
|
||||||
{% trans "File Links" %}
|
{% trans "File Links" %}
|
||||||
|
@ -8,3 +9,7 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
{% include "book/file_links/add_link_modal.html" with book=book active=True static=True id="file-link" %}
|
{% include "book/file_links/add_link_modal.html" with book=book active=True static=True id="file-link" %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
<script src="{% static "js/autocomplete.js" %}?v={{ js_cache }}"></script>
|
||||||
|
{% endblock %}
|
||||||
|
|
Loading…
Reference in a new issue