Add tag_autocomplete.js.
Instead of embedding the entire tag list in the search.html template every single time, this script loads the tags from the new, cache-enabled endpoint /all_tags.json. Then we can use html5 datalists to create autocomplete forms on the search and photo pages.
This commit is contained in:
parent
bbf07f4401
commit
8a12a24e8e
7 changed files with 121 additions and 15 deletions
|
@ -792,6 +792,15 @@ class PDBTagMixin:
|
|||
names = [row[0] for row in rows]
|
||||
return names
|
||||
|
||||
def get_all_synonyms(self):
|
||||
'''
|
||||
Return a dict mapping {synonym: mastertag} as strings.
|
||||
'''
|
||||
query = 'SELECT name, mastername FROM tag_synonyms'
|
||||
rows = self.sql_select(query)
|
||||
synonyms = {syn: tag for (syn, tag) in rows}
|
||||
return synonyms
|
||||
|
||||
def get_root_tags(self):
|
||||
'''
|
||||
Yield Tags that have no parent.
|
||||
|
|
|
@ -371,11 +371,9 @@ def get_search_core():
|
|||
def get_search_html():
|
||||
search_results = get_search_core()
|
||||
search_kwargs = search_results['search_kwargs']
|
||||
all_tags = common.P.get_all_tag_names()
|
||||
session = session_manager.get(request)
|
||||
response = flask.render_template(
|
||||
'search.html',
|
||||
all_tags=json.dumps(all_tags),
|
||||
next_page_url=search_results['next_page_url'],
|
||||
prev_page_url=search_results['prev_page_url'],
|
||||
photos=search_results['photos'],
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
import flask; from flask import request
|
||||
import json
|
||||
|
||||
import etiquette
|
||||
|
||||
from .. import caching
|
||||
from .. import common
|
||||
from .. import decorators
|
||||
from .. import jsonify
|
||||
|
@ -48,6 +50,14 @@ def post_tag_edit(specific_tag):
|
|||
|
||||
# Tag listings #####################################################################################
|
||||
|
||||
@site.route('/all_tags.json')
|
||||
@caching.cached_endpoint(max_age=0)
|
||||
def get_all_tag_names():
|
||||
all_tags = common.P.get_all_tag_names()
|
||||
all_synonyms = common.P.get_all_synonyms()
|
||||
response = {'tags': all_tags, 'synonyms': all_synonyms}
|
||||
return json.dumps(response)
|
||||
|
||||
@site.route('/tag/<specific_tag_name>')
|
||||
@site.route('/tags')
|
||||
@session_manager.give_token
|
||||
|
|
|
@ -121,3 +121,15 @@ function html_to_element(html)
|
|||
template.innerHTML = html;
|
||||
return template.content.firstChild;
|
||||
}
|
||||
|
||||
function normalize_tagname(tagname)
|
||||
{
|
||||
tagname = tagname.trim();
|
||||
tagname = tagname.toLocaleLowerCase();
|
||||
tagname = tagname.split(".");
|
||||
tagname = tagname[tagname.length-1];
|
||||
tagname = tagname.split("+")[0];
|
||||
tagname = tagname.replace(new RegExp(" ", 'g'), "_");
|
||||
tagname = tagname.replace(new RegExp("-", 'g'), "_");
|
||||
return tagname;
|
||||
}
|
||||
|
|
79
frontends/etiquette_flask/static/js/tag_autocomplete.js
Normal file
79
frontends/etiquette_flask/static/js/tag_autocomplete.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
var tag_autocomplete = {};
|
||||
|
||||
tag_autocomplete.tagset = {"tags": [], "synonyms": {}};
|
||||
|
||||
tag_autocomplete.DATALIST_ID = "tag_autocomplete_datalist"
|
||||
tag_autocomplete.init_datalist =
|
||||
function init_datalist()
|
||||
{
|
||||
var datalist;
|
||||
datalist = document.getElementById(tag_autocomplete.DATALIST_ID);
|
||||
if (!datalist)
|
||||
{
|
||||
var datalist = document.createElement("datalist");
|
||||
datalist.id = tag_autocomplete.DATALIST_ID;
|
||||
document.body.appendChild(datalist);
|
||||
}
|
||||
|
||||
delete_all_children(datalist);
|
||||
for (var index = 0; index < tag_autocomplete.tagset["tags"].length; index += 1)
|
||||
{
|
||||
var option = document.createElement("option");
|
||||
option.value = tag_autocomplete.tagset["tags"][index];
|
||||
datalist.appendChild(option);
|
||||
}
|
||||
for (var synonym in tag_autocomplete.tagset["synonyms"])
|
||||
{
|
||||
var option = document.createElement("option");
|
||||
option.value = tag_autocomplete.tagset["synonyms"][synonym] + "+" + synonym;
|
||||
datalist.appendChild(option);
|
||||
}
|
||||
}
|
||||
|
||||
tag_autocomplete.resolve =
|
||||
function resolve(tagname)
|
||||
{
|
||||
tagname = normalize_tagname(tagname);
|
||||
if (tag_autocomplete.tagset["tags"].indexOf(tagname) != -1)
|
||||
{
|
||||
return tagname;
|
||||
}
|
||||
if (tagname in tag_autocomplete.tagset["synonyms"])
|
||||
{
|
||||
return tag_autocomplete.tagset["synonyms"][tagname];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
tag_autocomplete.update_tagset_callback =
|
||||
function update_tagset_callback(response)
|
||||
{
|
||||
if (response["meta"]["status"] == 304)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (response["meta"]["status"] == 200)
|
||||
{
|
||||
tag_autocomplete.tagset = response["data"];
|
||||
if (document.getElementById(tag_autocomplete.DATALIST_ID))
|
||||
{
|
||||
tag_autocomplete.init_datalist();
|
||||
}
|
||||
return tag_autocomplete.tagset;
|
||||
}
|
||||
console.error(response);
|
||||
}
|
||||
|
||||
tag_autocomplete.update_tagset =
|
||||
function update_tagset()
|
||||
{
|
||||
console.log("Updating known tagset.");
|
||||
var url = "/all_tags.json";
|
||||
get(url, tag_autocomplete.update_tagset_callback);
|
||||
}
|
||||
|
||||
function on_pageload()
|
||||
{
|
||||
tag_autocomplete.update_tagset();
|
||||
}
|
||||
document.addEventListener("DOMContentLoaded", on_pageload);
|
|
@ -10,6 +10,7 @@
|
|||
<script src="/static/js/common.js"></script>
|
||||
<script src="/static/js/hotkeys.js"></script>
|
||||
<script src="/static/js/photoclipboard.js"></script>
|
||||
<script src="/static/js/tag_autocomplete.js"></script>
|
||||
|
||||
<style>
|
||||
#content_body
|
||||
|
@ -162,7 +163,7 @@
|
|||
<h4>Tags</h4>
|
||||
<ul id="this_tags">
|
||||
<li>
|
||||
<input id="add_tag_textbox" type="text" autofocus>
|
||||
<input id="add_tag_textbox" type="text" list="tag_autocomplete_datalist" autofocus>
|
||||
<button id="add_tag_button" class="green_button" onclick="submit_tag(receive_callback);">add</button>
|
||||
</li>
|
||||
{% set tags = photo.get_tags()|sort_tags %}
|
||||
|
@ -434,6 +435,8 @@ function move_hoverzoom(event)
|
|||
photo_img_holder.style.backgroundPosition=(-x)+"px "+(-y)+"px";
|
||||
}
|
||||
|
||||
tag_autocomplete.init_datalist();
|
||||
|
||||
setTimeout(
|
||||
/*
|
||||
When the screen is in column mode, the autofocusing of the tag box snaps the
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
<script src="/static/js/common.js"></script>
|
||||
<script src="/static/js/hotkeys.js"></script>
|
||||
<script src="/static/js/photoclipboard.js"></script>
|
||||
<script src="/static/js/tag_autocomplete.js"></script>
|
||||
|
||||
<style>
|
||||
form
|
||||
|
@ -171,7 +172,7 @@ form
|
|||
</li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<li><input id="search_builder_{{tagtype}}_input" type="text"></li>
|
||||
<li><input id="search_builder_{{tagtype}}_input" type="text" list="tag_autocomplete_datalist"></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
@ -525,10 +526,9 @@ function tags_on_this_page_hook()
|
|||
*/
|
||||
var tagname = this.innerHTML.split(/\./);
|
||||
tagname = tagname[tagname.length-1];
|
||||
var qualname = ALL_TAGS[tagname];
|
||||
add_searchtag(
|
||||
input_musts,
|
||||
qualname,
|
||||
tagname,
|
||||
inputted_musts,
|
||||
"search_builder_musts_inputted"
|
||||
);
|
||||
|
@ -546,13 +546,9 @@ function tag_input_hook(box, inputted_list, li_class)
|
|||
if (!box.value)
|
||||
{return;}
|
||||
|
||||
var value = box.value.toLocaleLowerCase();
|
||||
value = value.split(".");
|
||||
value = value[value.length-1];
|
||||
value = value.split("+")[0];
|
||||
value = value.replace(new RegExp(" ", 'g'), "_");
|
||||
value = value.replace(new RegExp("-", 'g'), "_");
|
||||
if (ALL_TAGS.indexOf(value) == -1)
|
||||
var value = box.value;
|
||||
value = tag_autocomplete.resolve(value);
|
||||
if (value === null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@ -561,8 +557,7 @@ function tag_input_hook(box, inputted_list, li_class)
|
|||
box.value = "";
|
||||
}
|
||||
|
||||
|
||||
ALL_TAGS = {{all_tags|safe}};
|
||||
tag_autocomplete.init_datalist();
|
||||
var input_musts = document.getElementById("search_builder_musts_input");
|
||||
var input_mays = document.getElementById("search_builder_mays_input");
|
||||
var input_forbids = document.getElementById("search_builder_forbids_input");
|
||||
|
|
Loading…
Reference in a new issue