diff --git a/frontends/etiquette_flask/templates/tags.html b/frontends/etiquette_flask/templates/tags.html index b39c2d1..f71271e 100644 --- a/frontends/etiquette_flask/templates/tags.html +++ b/frontends/etiquette_flask/templates/tags.html @@ -138,7 +138,6 @@ h2, h3 > Delete - {% set parents = specific_tag.get_parents() %} @@ -171,26 +170,31 @@ h2, h3 {{tag_object.tag_object(tag, link="search_musts", innertext="(+)")}} {{tag_object.tag_object(tag, link="search_forbids", innertext="(x)")}} {{tag_object.tag_object(tag, link="info", innertext=qualified_name, with_alt_description=True)-}} + {% if '.' in qualified_name -%} - {{-''-}} - - + > + Unlink + + {%- else -%} + + {% endif %} {% if include_synonyms %} @@ -207,7 +211,9 @@ h2, h3 data-confirm="Remove" data-confirm-class="remove_tag_button_perm red_button" data-cancel-class="remove_tag_button_perm gray_button" - >Remove + > + Remove + {% endfor %} {% endif %} @@ -258,141 +264,12 @@ var add_tag_button = document.getElementById('add_tag_button'); var message_area = document.getElementById('message_area'); common.bind_box_to_button(add_tag_textbox, add_tag_button, false); -TEMPLATE_BUTTON_DELETE_TAG = ``; - -TEMPLATE_BUTTON_REMOVE_CHILD = ``; - -TEMPLATE_BUTTON_REMOVE_SYNONYM = ``; - -TEMPLATE_TAG_LI = `
  • (+) -(x) -{tag_name}
  • `; - -function get_all_tag_objects() -{ return Array.from(document.querySelectorAll(".tag_object[href^='/tag/']")); } - -function get_tag_objects_for_descendant(tag_name, child_name) -{ return get_tag_objects_matching(`(^|\\.)${re_escape(tag_name)}\\.${re_escape(child_name)}($|\\.|\\+)`); } - -function get_tag_objects_for_descendants(tag_name) -{ return get_tag_objects_matching(`(^|\\.)${re_escape(tag_name)}\\.`); } - -function get_tag_objects_for_synonym(synonym) -{ return get_tag_objects_matching(`\\+${re_escape(synonym)}$`); } - -function get_tag_objects_for_non_root_tag(tag_name) -{ return get_tag_objects_matching(`\\.${re_escape(tag_name)}($|\\+)`); } - -function get_tag_objects_for_non_root_tag_and_descendants(tag_name) -{ return get_tag_objects_matching(`\\.${re_escape(tag_name)}($|\\.|\\+)`); } - -function get_tag_objects_for_root_tag(tag_name) -{ return get_tag_objects_matching(`^${re_escape(tag_name)}($|\\+)`); } - -function get_tag_objects_for_root_tag_and_descendants(tag_name) -{ return get_tag_objects_matching(`^${re_escape(tag_name)}($|\\.|\\+)`); } - -function get_tag_objects_for_tag(tag_name) -{ return get_tag_objects_matching(`(^|\\.)${re_escape(tag_name)}$`); } - -function get_tag_objects_for_tag_and_descendants(tag_name) -{ return get_tag_objects_matching(`(^|\\.)${re_escape(tag_name)}($|\\.|\\+)`); } - -function get_tag_objects_for_tag_and_synonyms(tag_name) -{ return get_tag_objects_matching(`(^|\\.)${re_escape(tag_name)}($|\\+)`); } - -function get_tag_objects_matching(regex) -{ - regex = new RegExp(regex); - const ret = get_all_tag_objects().filter(tag_object => tag_object.innerText.match(regex)); - return ret; -} - -function split_exclusive(text, tag_name) -{ - /* - Given text="a.b.c.d.e", tag_name"c", return "d.e". - */ - const regex = `(?:^|\\.)${re_escape(tag_name)}(?:$|\\.)`; - const splitted = text.split(new RegExp(regex)); - if (splitted.length == 1) - { return null; } - const descendantry = splitted.pop(); - return descendantry; -} - -function split_inclusive(text, tag_name) -{ - /* - Given text="a.b.c.d.e", tag_name"c", return "c.d.e". - */ - const descendantry = split_exclusive(text, tag_name); - if (descendantry === null) - { return null; } - if (descendantry === "") - { return tag_name; } - return tag_name + "." + descendantry; -} - function tag_object_from_li(li) { const tag_objects = li.getElementsByClassName("tag_object"); return tag_objects[tag_objects.length - 1]; } -function lift_tag_object(tag_object, from_parent) -{ - const descendantry = split_exclusive(tag_object.innerText, from_parent); - const regex = `(^|\\.)${re_escape(from_parent)}\\.`; - tag_object.innerText = tag_object.innerText.replace(new RegExp(regex), "$1"); - const is_now_root = tag_object.innerText.indexOf(descendantry) == 0; - if (! is_now_root) - { - return; - } - const other_parents = get_tag_objects_matching(`\\.${re_escape(descendantry)}$`) - if (other_parents.length == 0) - { - return; - } - const li = tag_object.closest("li"); - li.parentElement.removeChild(li); -} - -function re_escape(s) -{ - // Thank you Pi Marillion. - // https://stackoverflow.com/a/30851002 - return s.replace(/[^A-Za-z0-9_]/g, '\\$&'); -} - - -// FORM FUNCTIONS ////////////////////////////////////////////////////////////// - function easybake_form() { const easybake_string = add_tag_textbox.value; @@ -454,69 +331,6 @@ function remove_synonym_form(event) return api.tags.remove_synonym(tag_name, synonym, tag_action_callback); } -// CALLBACKS /////////////////////////////////////////////////////////////////// - -function easybake_callback(response) -{ - tag_action_callback(response); - if (response.meta.status !== 200) - {return;} - for (const data of response.data) - { - if (!("action" in data)) - {continue;} - const action = data.action; - if (action == "new_tag") - { - const tag_name = data.tagname; - new_tag(tag_name); - } - else if (action == "new_synonym") - { - const [tag_name, synonym] = data.tagname.split("+"); - new_synonym(tag_name, synonym); - } - else if (action == "join_group") - { - const [parent_name, child_name] = data.tagname.split("."); - join_group(parent_name, child_name); - } - else if (action == "rename_tag") - { - const [rename_from, rename_to] = data.tagname.split("="); - rename_tag(rename_from, rename_to); - } - } -} - -function delete_tag_callback(response) -{ - tag_action_callback(response); - if (response.meta.status !== 200) - {return;} - const tag_name = response.data.tagname; - delete_tag(tag_name); -} - -function remove_child_callback(response) -{ - tag_action_callback(response); - if (response.meta.status !== 200) - {return;} - const [parent_name, tag_name] = response.data.tagname.split("."); - remove_child(parent_name, tag_name); -} - -function remove_synonym_callback(response) -{ - tag_action_callback(response); - if (response.meta.status !== 200) - {return;} - - const synonym = response.data.synonym; - remove_synonym(synonym); -} - function tag_action_callback(response) { let datas = response.data; @@ -566,216 +380,6 @@ function tag_action_callback(response) } } -// UI UPDATERS ///////////////////////////////////////////////////////////////// - -function new_tag(tag_name) -{ - const template = TEMPLATE_TAG_LI.replace(/\{tag_name\}/g, tag_name); - const new_li = common.html_to_element(template); - add_buttons_to_li(new_li); - document.getElementById("tag_list").appendChild(new_li); - sort_tag_objects(); -} - -function new_synonym(tag_name, synonym) -{ - for (const tag_object of get_tag_objects_for_tag(tag_name)) - { - const li = tag_object.closest("li"); - const new_li = li.cloneNode(true); - tag_object_from_li(new_li).innerText += `+${synonym}`; - li.parentElement.appendChild(new_li); - add_buttons_to_li(new_li); - } - sort_tag_objects(); -} - -function join_group(parent_name, child_name) -{ - console.log(parent_name + " " + SPECIFIC_TAG); - if (parent_name === SPECIFIC_TAG) - { - console.log("GO!"); - return new_tag(`${parent_name}.${child_name}`); - } - const parent_tags = get_tag_objects_for_tag(parent_name); - const seen_names = new Set(); - for (child_tag of get_tag_objects_for_tag_and_descendants(child_name)) - { - const descendantry = split_inclusive(child_tag.innerText, child_name); - if (seen_names.has(descendantry)) - { break; } - seen_names.add(descendantry); - const child_li = child_tag.closest("li"); - for (const parent_tag of parent_tags) - { - const parent_li = parent_tag.closest("li"); - const new_li = child_li.cloneNode(true); - tag_object_from_li(new_li).innerText = parent_tag.innerText + "." + descendantry; - parent_li.parentElement.appendChild(new_li); - add_buttons_to_li(new_li); - } - } - - for (const tag_object of get_tag_objects_for_root_tag_and_descendants(child_name)) - { - const li = tag_object.closest("li"); - li.parentElement.removeChild(li); - } - sort_tag_objects(); -} - -function rename_tag(rename_from, rename_to) -{ - if (rename_from == rename_to) - { return; } - for (const tag_object of get_all_tag_objects()) - { - tag_object.innerText = tag_object.innerText.replace(new RegExp(`(^|\\.)${re_escape(rename_from)}($|\\.|\\+)`), `$1${rename_to}$2`); - } - sort_tag_objects(); -} - -function delete_tag(tag_name) -{ - const tag_objects = get_tag_objects_for_tag_and_synonyms(tag_name); - for (const tag_object of tag_objects) - { - const li = tag_object.closest("li"); - li.parentElement.removeChild(li); - } - const child_tags = get_tag_objects_for_descendants(tag_name); - for (const child_tag of child_tags) - { - lift_tag_object(child_tag, tag_name); - } - update_all_li_buttons(); - sort_tag_objects(); -} - -function remove_child(parent_name, child_name) -{ - const tag_objects = get_tag_objects_for_descendant(parent_name, child_name); - const seen_names = new Set(); - for (const tag_object of tag_objects) - { - const descendantry = split_exclusive(tag_object.innerText, parent_name); - if (descendantry === null) - { - continue; - } - const tag_li = tag_object.closest("li"); - if (seen_names.has(descendantry)) - { - tag_li.parentElement.removeChild(tag_li); - continue; - } - tag_object.innerText = descendantry; - update_li_buttons(tag_li); - seen_names.add(descendantry); - } - - const child_as_root = get_tag_objects_for_root_tag_and_descendants(child_name); - const child_as_non_root = get_tag_objects_for_non_root_tag(child_name) - if (child_as_non_root.length > 0) - { - for (const tag_object of child_as_root) - { - const tag_li = tag_object.closest("li"); - tag_li.parentElement.removeChild(tag_li); - } - } - sort_tag_objects(); -} - -function remove_synonym(synonym) -{ - for (const tag_object of get_tag_objects_for_synonym(synonym)) - { - const li = tag_object.closest("li"); - li.parentElement.removeChild(li); - } -} - -function add_buttons_to_li(li) -{ - for (const existing of Array.from(li.getElementsByClassName("confirm_holder"))) - { - li.removeChild(existing); - } - li.appendChild(common.html_to_element(TEMPLATE_BUTTON_DELETE_TAG)); - li.appendChild(common.html_to_element(TEMPLATE_BUTTON_REMOVE_CHILD)); - li.appendChild(common.html_to_element(TEMPLATE_BUTTON_REMOVE_SYNONYM)); - for (const button of Array.from(li.getElementsByClassName("button_with_confirm"))) - { - common.init_button_with_confirm(button); - } - update_li_buttons(li); -} - -function add_buttons_to_all_lis() -{ - const lis = document.getElementById("tag_list").children; - for (const li of lis) - { - add_buttons_to_li(li); - } -} - -function update_li_buttons(li) -{ - const tag_object = tag_object_from_li(li); - const delete_button = li.querySelector(".confirm_holder_delete_tag"); - const unlink_button = li.querySelector(".confirm_holder_remove_child"); - const synonym_button = li.querySelector(".confirm_holder_remove_synonym"); - if (tag_object.innerText.includes("+")) - { - synonym_button.classList.remove("hidden"); - delete_button.classList.add("hidden"); - unlink_button.classList.add("hidden"); - } - else if (tag_object.innerText.includes(".")) - { - unlink_button.classList.remove("hidden"); - delete_button.classList.add("hidden"); - synonym_button.classList.add("hidden"); - } - else - { - delete_button.classList.remove("hidden"); - unlink_button.classList.add("hidden"); - synonym_button.classList.add("hidden"); - } -} - -function update_all_li_buttons() -{ - const lis = document.getElementById("tag_list").children; - for (const li of lis) - { - update_li_buttons(li); - } -} - -function sort_tag_objects() -{ - const start = performance.now(); - function compare(li1, li2) - { - const tag1 = tag_object_from_li(li1).innerText; - const tag2 = tag_object_from_li(li2).innerText; - return tag1 < tag2 ? -1 : 1; - } - const tag_list = document.getElementById("tag_list"); - const lis = Array.from(tag_list.children); - lis.sort(compare); - for (const li of lis) - { - tag_list.appendChild(li); - } - const end = performance.now(); -} - {% if specific_tag is not none %} function on_open(ed, edit_element_map) { @@ -833,11 +437,5 @@ var name_text = document.getElementById("name_text"); var description_text = document.getElementById("description_text"); var ed = new editor.Editor([name_text, description_text], on_open, on_save, on_cancel); {% endif %} - -function on_pageload() -{ - // window.setTimeout(add_buttons_to_all_lis, 0); -} -document.addEventListener("DOMContentLoaded", on_pageload);