From: Christian Heller <c.heller@plomlompom.de>
Date: Sat, 15 Feb 2025 06:22:46 +0000 (+0100)
Subject: Improve tag selection interface in files index.
X-Git-Url: https://plomlompom.com/repos/%7B%7Bdb.prefix%7D%7D/static/%7B%7Bprefix%7D%7D/todo?a=commitdiff_plain;h=40533f448af612655d622509c164e6cd9efd50ab;p=ytplom

Improve tag selection interface in files index.
---

diff --git a/src/templates/_macros.tmpl b/src/templates/_macros.tmpl
index 9c70226..602d2d3 100644
--- a/src/templates/_macros.tmpl
+++ b/src/templates/_macros.tmpl
@@ -3,3 +3,12 @@
 {% if display_name %}{{display_name}}{% else %}{{target}}{% endif %}
 {% if cond %}</a>{% endif %}
 {% endmacro %}
+
+
+{% macro js_new_child_to() %}
+function new_child_to(tag, parent, textContent='') {
+    const el = document.createElement(tag);
+    parent.appendChild(el);
+    el.textContent = textContent;
+    return el; }
+{% endmacro %}
diff --git a/src/templates/files.tmpl b/src/templates/files.tmpl
index e447c2a..e0fc5b6 100644
--- a/src/templates/files.tmpl
+++ b/src/templates/files.tmpl
@@ -1,11 +1,62 @@
 {% extends '_base.tmpl' %}
 
 
+{% block script %}
+{{ macros.js_new_child_to() }}
+
+const all_tags = {{showable_tags|tojson|safe}};
+var needed_tags = {{needed_tags|tojson|safe}};
+
+function select_tag() {
+  if (tags_select.selectedIndex < 1) {
+    return;
+  }
+  const chosen_tag = document.getElementById('tags_select').value;
+  needed_tags.push(chosen_tag);
+  reload_selector();
+}
+
+function reload_selector() {
+  const tags_select = document.getElementById('tags_select');
+  while (tags_select.options.length > 0) {
+    tags_select.remove(0);
+  }
+  new_child_to('option', tags_select, 'add tag');
+  all_tags.forEach((tag) => {
+    if (needed_tags.includes(tag)) {
+      return;
+    }
+    const option = new_child_to('option', tags_select, tag);
+  });
+  const tags_div = document.getElementById("tags");
+  tags_div.innerHTML = '';
+  needed_tags.forEach((chosen_tag) => {
+    const tag_text_node = document.createTextNode(` ${chosen_tag} `);
+    tags_div.appendChild(tag_text_node);
+    const btn_del = new_child_to('button', tags_div, 'x');
+    btn_del.onclick = function() {
+      tag_text_node.remove();
+      btn_del.remove();
+      needed_tags = needed_tags.filter(tag => tag !== chosen_tag);
+      reload_selector();
+    };
+    const input = new_child_to('input', tags_div);
+    input.type = 'hidden';
+    input.name = 'needed_tag';
+    input.value = chosen_tag;
+  });
+}
+
+window.addEventListener('load', reload_selector);
+{% endblock %}
+
+
 {% block body %}
 <form method="GET">
-filter filename: <input name="filter_path" value="{{filter_path}}" />
-needed tags: <input name="needed_tags" value="{{needed_tags}}" />
-show absent: <input type="checkbox" name="show_absent" {% if show_absent %}checked{% endif %}/>
+<input type="checkbox" name="show_absent" {% if show_absent %}checked{% endif %}/> show absent<br />
+filename: <input name="filter_path" value="{{filter_path}}" /><br />
+tags: <span id="tags"></span><br />
+<select id="tags_select" onchange="select_tag()"></select><br />
 <input type="submit" value="filter" />
 </form>
 <p>known files (shown: {{files|length}}):</p>
diff --git a/src/templates/playlist.tmpl b/src/templates/playlist.tmpl
index c4cdeb7..a27d4a2 100644
--- a/src/templates/playlist.tmpl
+++ b/src/templates/playlist.tmpl
@@ -2,17 +2,12 @@
 
 
 {% block script %}
+{{ macros.js_new_child_to() }}
 
 const CLS_PLAYLIST_ROW = 'playlist_row';
 events_params += 'playlist=1';
 var first_load = true;
 
-function new_child_to(tag, parent, textContent='') {
-    const el = document.createElement(tag);
-    parent.appendChild(el);
-    el.textContent = textContent;
-    return el; }
-
 event_handlers.push(function(data) {  // update playlist
     const table = document.getElementById('playlist_rows');
     var old_rows = document.getElementsByClassName(CLS_PLAYLIST_ROW);
diff --git a/src/ytplom/http.py b/src/ytplom/http.py
index 4f30f13..a17b00e 100644
--- a/src/ytplom/http.py
+++ b/src/ytplom/http.py
@@ -301,20 +301,22 @@ class _TaskHandler(PlomHttpHandler):
 
     def _send_files_index(self) -> None:
         filter_path = FilterStr(self.params.first_for('filter_path'))
-        needed_tags_str = self.params.first_for('needed_tags')
         show_absent = bool(self.params.first_for('show_absent'))
+        needed_tags_list = self.params.all_for('needed_tag')
         with DbConn() as conn:
             files = VideoFile.get_filtered(
                     conn,
                     filter_path,
-                    TagSet.from_joined(needed_tags_str),
+                    TagSet(set(needed_tags_list)),
                     show_absent)
+            showable_tags = sorted(list(VideoFile.all_tags_showable(conn)))
         files.sort(key=lambda t: t.rel_path)
         self._send_rendered_template(_NAME_TEMPLATE_FILES,
                                      {'files': files,
                                       'selected': 'files',
                                       'filter_path': filter_path,
-                                      'needed_tags': needed_tags_str,
+                                      'showable_tags': showable_tags,
+                                      'needed_tags': needed_tags_list,
                                       'show_absent': show_absent})
 
     def _send_missing_json(self) -> None:
diff --git a/src/ytplom/misc.py b/src/ytplom/misc.py
index 51a39aa..010a2fb 100644
--- a/src/ytplom/misc.py
+++ b/src/ytplom/misc.py
@@ -390,9 +390,17 @@ class VideoFile(DbData):
             and needed_tags_seen.whitelisted(cls.tags_display_whitelist
                                              ).are_all_in(f.tags)]
 
+    @classmethod
+    def all_tags_showable(cls, conn) -> TagSet:
+        """Show all used tags passing .tags_display_whitelist."""
+        tags = TagSet()
+        for file in cls.get_all(conn):
+            tags.add(file.tags.whitelisted(cls.tags_display_whitelist))
+        return tags
+
     @property
     def tags_showable(self) -> TagSet:
-        """Show .tags passing .tags_display_whitelist, if latter set."""
+        """Show .tags passing .tags_display_whitelist."""
         return self.tags.whitelisted(self.tags_display_whitelist)
 
     def unused_tags(self, conn: DbConn) -> TagSet: