Add album_autocomplete.js, so "Add child" box can autocomplete.

This makes putting albums together a little easier, though datalist
performance still leaves a lot to be desired.
This commit is contained in:
voussoir 2020-10-03 18:37:08 -07:00
parent 4e3e2fea12
commit 86c09aedc1
5 changed files with 108 additions and 14 deletions

View file

@ -1,8 +1,10 @@
import flask; from flask import request import flask; from flask import request
import time
import urllib.parse import urllib.parse
import etiquette import etiquette
from .. import caching
from .. import common from .. import common
from .. import decorators from .. import decorators
from .. import jsonify from .. import jsonify
@ -154,6 +156,13 @@ def post_album_edit(album_id):
# Album listings ################################################################################### # Album listings ###################################################################################
@site.route('/all_albums.json')
@caching.cached_endpoint(max_age=0)
def get_all_album_names():
all_albums = {album.display_name: album.id for album in common.P.get_albums()}
response = {'updated': int(time.time()), 'albums': all_albums}
return jsonify.make_json_response(response)
def get_albums_core(): def get_albums_core():
albums = list(common.P.get_root_albums()) albums = list(common.P.get_root_albums())
albums.sort(key=lambda x: x.display_name.lower()) albums.sort(key=lambda x: x.display_name.lower())

View file

@ -0,0 +1,59 @@
const album_autocomplete = {};
album_autocomplete.albums = {};
album_autocomplete.DATALIST_ID = "album_autocomplete_datalist";
album_autocomplete.datalist = null;
album_autocomplete.on_load_hooks = [];
////////////////////////////////////////////////////////////////////////////////////////////////////
album_autocomplete.init_datalist =
function init_datalist()
{
if (album_autocomplete.datalist)
{
return;
}
console.log("Init album_autocomplete datalist.");
const datalist = document.createElement("datalist");
datalist.id = album_autocomplete.DATALIST_ID;
document.body.appendChild(datalist);
const fragment = document.createDocumentFragment();
for (const album_name in album_autocomplete.albums)
{
const album_id = album_autocomplete.albums[album_name];
const option = document.createElement("option");
option.value = album_id;
option.innerText = album_name;
fragment.appendChild(option);
}
datalist.appendChild(fragment);
album_autocomplete.datalist = datalist;
for (const hook of album_autocomplete.on_load_hooks)
{
hook(datalist);
}
}
album_autocomplete.get_all_albums_callback =
function get_all_albums_callback(response)
{
if (response.meta.status !== 200)
{
console.error(response);
return;
}
album_autocomplete.albums = response.data.albums;
setTimeout(album_autocomplete.init_datalist, 0);
}
album_autocomplete.on_pageload =
function on_pageload()
{
setTimeout(api.albums.get_all_albums(album_autocomplete.get_all_albums_callback), 0);
}
document.addEventListener("DOMContentLoaded", album_autocomplete.on_pageload);

View file

@ -61,6 +61,13 @@ function _delete(album_id, callback)
common.post(url, null, callback); common.post(url, null, callback);
} }
api.albums.get_all_albums =
function get_all_albums(callback)
{
const url = "/all_albums.json";
common.get(url, callback);
}
api.albums.edit = api.albums.edit =
function edit(album_id, title, description, callback) function edit(album_id, title, description, callback)
{ {

View file

@ -4,26 +4,24 @@ tag_autocomplete.tags = new Set();
tag_autocomplete.synonyms = {}; tag_autocomplete.synonyms = {};
tag_autocomplete.DATALIST_ID = "tag_autocomplete_datalist"; tag_autocomplete.DATALIST_ID = "tag_autocomplete_datalist";
tag_autocomplete.datalist = null;
tag_autocomplete.on_load_hooks = [];
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
tag_autocomplete.init_datalist = tag_autocomplete.init_datalist =
function init_datalist() function init_datalist()
{ {
console.log("Init datalist."); if (tag_autocomplete.datalist)
let datalist;
datalist = document.getElementById(tag_autocomplete.DATALIST_ID);
if (datalist)
{ {
return; return;
} }
console.log("Init tag_autocomplete datalist.");
datalist = document.createElement("datalist"); const datalist = document.createElement("datalist");
datalist.id = tag_autocomplete.DATALIST_ID; datalist.id = tag_autocomplete.DATALIST_ID;
document.body.appendChild(datalist); document.body.appendChild(datalist);
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
common.delete_all_children(datalist);
for (const tag_name of tag_autocomplete.tags) for (const tag_name of tag_autocomplete.tags)
{ {
const option = document.createElement("option"); const option = document.createElement("option");
@ -37,6 +35,12 @@ function init_datalist()
fragment.appendChild(option); fragment.appendChild(option);
} }
datalist.appendChild(fragment); datalist.appendChild(fragment);
tag_autocomplete.datalist = datalist;
for (const hook of tag_autocomplete.on_load_hooks)
{
hook(datalist);
}
} }
tag_autocomplete.normalize_tagname = tag_autocomplete.normalize_tagname =
@ -101,11 +105,7 @@ function resolve(tagname)
tag_autocomplete.get_all_tags_callback = tag_autocomplete.get_all_tags_callback =
function get_all_tags_callback(response) function get_all_tags_callback(response)
{ {
if (response["meta"]["status"] == 304) if (response.meta.status !== 200)
{
return;
}
if (response["meta"]["status"] != 200)
{ {
console.error(response); console.error(response);
return; return;
@ -113,8 +113,7 @@ function get_all_tags_callback(response)
tag_autocomplete.tags = new Set(response.data.tags); tag_autocomplete.tags = new Set(response.data.tags);
tag_autocomplete.synonyms = response.data.synonyms; tag_autocomplete.synonyms = response.data.synonyms;
setTimeout(() => tag_autocomplete.init_datalist(), 0); setTimeout(tag_autocomplete.init_datalist, 0);
return tag_autocomplete.tagset;
} }
tag_autocomplete.on_pageload = tag_autocomplete.on_pageload =

View file

@ -141,6 +141,7 @@ const ALBUM_ID = undefined;
{% if theme %}<link rel="stylesheet" href="/static/css/theme_{{theme}}.css">{% endif %} {% if theme %}<link rel="stylesheet" href="/static/css/theme_{{theme}}.css">{% endif %}
<script src="/static/js/common.js"></script> <script src="/static/js/common.js"></script>
<script src="/static/js/api.js"></script> <script src="/static/js/api.js"></script>
<script src="/static/js/album_autocomplete.js"></script>
<script src="/static/js/spinner.js"></script> <script src="/static/js/spinner.js"></script>
<script src="/static/js/editor.js"></script> <script src="/static/js/editor.js"></script>
<script src="/static/js/hotkeys.js"></script> <script src="/static/js/hotkeys.js"></script>
@ -180,6 +181,7 @@ const ALBUM_ID = undefined;
<button <button
class="green_button button_with_confirm" class="green_button button_with_confirm"
data-holder-id="add_child_holder"
data-is-input="1" data-is-input="1"
data-prompt="Child ID" data-prompt="Child ID"
data-cancel-class="gray_button" data-cancel-class="gray_button"
@ -368,6 +370,24 @@ function on_cancel(ed, edit_element_map, display_element_map)
const title_text = document.getElementById("title_text"); const title_text = document.getElementById("title_text");
const description_text = document.getElementById("description_text"); const description_text = document.getElementById("description_text");
const ed = new editor.Editor([title_text, description_text], on_open, on_save, on_cancel); const ed = new editor.Editor([title_text, description_text], on_open, on_save, on_cancel);
function add_album_datalist_on_load(datalist)
{
/*
I found that the `list` property must be set by setAttribute, not
regular assignment, and it must be provided the ID of the datalist, not
the datalist object itself. Furthermore, it cannot be done until the
datalist is ready -- I tried adjusting the button_with_confirm
initializer to let me set the datalist during the input's construction,
but at that point the datalist prep usually / certainly hasn't run yet
and it didn't work. All that is to say I had to add this on_load hook
function to only call setAttribute after the datalist has been prepared.
*/
const holder = document.getElementById("add_child_holder");
const input = holder.getElementsByTagName("input")[0];
input.setAttribute("list", "album_autocomplete_datalist");
}
album_autocomplete.on_load_hooks.push(add_album_datalist_on_load);
</script> </script>
{% endif %} {## Shared ############################################################################} {% endif %} {## Shared ############################################################################}