refactor(js): tag-utils uses display_name and tag_id

getTagDisplayName is now a passthrough; post-refactor names are bare
and callers that need the character+fandom suffix pass tag.display_name
from the server. createTagChipHtml builds ?tag_id=<int> URLs and uses
display_name for the label. bulk-select.js callers pass display_name
directly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 16:19:52 -04:00
parent c9fce48a39
commit 27609043e8
2 changed files with 33 additions and 33 deletions
+2 -2
View File
@@ -270,7 +270,7 @@
dom.commonTags.innerHTML = tags.map(t => {
const icon = getTagIcon(t.kind);
const display = getTagDisplayName(t.name, t.kind);
const display = t.display_name || t.name;
const escapedName = escapeHtml(t.name);
const escapedDisplay = escapeHtml(display);
return `<span class="tag-chip removable" data-name="${escapedName}">
@@ -605,7 +605,7 @@
dom.autocomplete.innerHTML = tags.map((t, i) => {
const icon = getTagIcon(t.kind);
const displayName = getTagDisplayName(t.name, t.kind);
const displayName = t.display_name || t.name;
return `<div class="tag-autocomplete-item" data-index="${i}" data-name="${escapeHtml(t.name)}">
<span>${icon} ${escapeHtml(displayName)}</span>
<span class="tag-kind">${t.kind || 'user'}</span>
+31 -31
View File
@@ -24,36 +24,36 @@
}
/**
* Get display name for a tag, stripping the prefix if present
* @param {string} name - Full tag name (e.g., "artist:Name")
* @param {string} [kind] - Optional tag kind for context
* @returns {string} Display name without prefix
* Get display name for a tag.
*
* Post-refactor tag names are stored bare (no kind: prefix), so this helper
* is now a near-passthrough. Callers that need character+fandom qualified
* names (e.g. "Ruby Rose (RWBY)") should pass `tag.display_name` from the
* server response directly.
*
* @param {string} name - Bare tag name
* @returns {string} The name unchanged
*/
function getTagDisplayName(name, kind) {
// For prefixed kinds, strip the prefix
if (kind && ['artist', 'character', 'series', 'fandom', 'rating'].includes(kind)) {
return name.includes(':') ? name.split(':', 2)[1] : name;
}
// If no kind specified but has colon, assume it's prefixed
if (!kind && name.includes(':')) {
return name.split(':', 2)[1];
}
function getTagDisplayName(name) {
return name;
}
/**
* Get display name for tag overlay (used in gallery items)
* Returns name with # prefix for unprefixed user tags
* @param {string} name - Full tag name
* Get overlay-formatted display name for a tag.
*
* User-kind (untyped) tags get a '#' hashtag prefix; every other kind
* gets the bare name (or whatever display form the caller passed).
*
* @param {string} name - Bare tag name or pre-rendered display_name
* @param {string} kind - Tag kind
* @returns {string} Display name for overlay
* @returns {string} Overlay label
*/
function getTagDisplayNameForOverlay(name, kind) {
if (['artist', 'character', 'series', 'fandom', 'rating'].includes(kind)) {
return name.includes(':') ? name.split(':', 2)[1] : name;
}
if (!kind || kind === 'user') {
return '#' + name;
}
return name;
}
/**
* Escape HTML special characters
@@ -68,13 +68,13 @@
/**
* Format a tag for display with icon and name
* @param {Object} tag - Tag object with name and kind
* @param {Object} tag - Tag object with name, kind, and optional display_name
* @returns {string} Formatted HTML string
*/
function formatTagHtml(tag) {
const icon = getTagIcon(tag.kind);
const displayName = getTagDisplayName(tag.name, tag.kind);
const escaped = escapeHtml(displayName);
const label = tag.display_name || tag.name;
const escaped = escapeHtml(label);
if (icon !== '#') {
return `${icon} ${escaped}`;
@@ -83,21 +83,21 @@
}
/**
* Create tag chip HTML for gallery overlays
* @param {Object} tag - Tag object with name and kind
* Create tag chip HTML for gallery overlays.
*
* @param {Object} tag - Tag object with id, name, kind, and optional display_name
* @param {boolean} [stopPropagation=true] - Add onclick to stop propagation
* @returns {string} HTML string for tag chip link
*/
function createTagChipHtml(tag, stopPropagation = true) {
const icon = getTagIcon(tag.kind);
const displayName = getTagDisplayNameForOverlay(tag.name, tag.kind);
const encodedName = encodeURIComponent(tag.name);
const escapedTitle = escapeHtml(tag.name);
const escapedDisplay = escapeHtml(displayName);
const prefix = icon !== '#' ? icon + ' ' : '#';
const label = tag.display_name || getTagDisplayNameForOverlay(tag.name, tag.kind);
const escapedLabel = escapeHtml(label);
const escapedTitle = escapeHtml(tag.display_name || tag.name);
const prefix = icon !== '#' ? icon + ' ' : '';
const onclick = stopPropagation ? ' onclick="event.stopPropagation()"' : '';
return `<a class="tag-chip" href="/gallery?tag=${encodedName}" title="Filter by ${escapedTitle}"${onclick}>${prefix}${escapedDisplay}</a>`;
return `<a class="tag-chip tag-chip-${tag.kind || 'user'}" href="/gallery?tag_id=${tag.id}" title="Filter by ${escapedTitle}"${onclick}>${prefix}${escapedLabel}</a>`;
}
// Export to window.TagUtils