Fix category display and link behaviour in operation popovers

- Use originalName for category lookup as highlightSearchStrings modifies
  this.name with <b> tags, which broke category display for name-matched
  search results
- Derive category ID from link text since Bootstrap's popover sanitizer
  strips custom data-* attributes
- Don't hide all categories before showing the target; the accordion
  data-parent behaviour handles that, and the manual hide caused a
  transition race that closed the target category instead of opening it
This commit is contained in:
Allan Leary 2026-07-14 11:04:24 +01:00
parent f15ad10b94
commit 05dea56d7d
2 changed files with 22 additions and 13 deletions

View File

@ -27,6 +27,7 @@ class HTMLOperation {
this.manager = manager;
this.name = name;
this.originalName = name;
this.description = config.description;
this.infoURL = config.infoURL;
this.manualBake = config.manualBake || false;
@ -86,11 +87,11 @@ class HTMLOperation {
return "";
}
// Find all categories this operation belongs to, excluding Favourites
// Use originalName because this.name may have been modified by highlightSearchStrings
const categories = [];
for (let i = 0; i < this.app.categories.length; i++) {
const cat = this.app.categories[i];
if (cat.name !== "Favourites" && cat.ops.includes(this.name)) {
if (cat.name !== "Favourites" && cat.ops.includes(this.originalName)) {
categories.push(cat.name);
}
}
@ -99,11 +100,12 @@ class HTMLOperation {
return "";
}
// Build the category links
const categoryLinks = categories.map(catName => {
const catId = "cat" + catName.replace(/[\s/\-:_]/g, "");
return `<a class="op-category-link" data-category="${catId}">${catName}</a>`;
}).join(", ");
// Build the category links. Note that Bootstrap's popover sanitizer strips
// custom data-* attributes, so the category name is carried in the link text
// and resolved to a category ID by OperationsWaiter.categoryLinkClick.
const categoryLinks = categories.map(catName =>
`<a href='#' class='op-category-link'>${Utils.escapeHtml(catName)}</a>`
).join(", ");
return `<hr>Category: ${categoryLinks}`;
}

View File

@ -354,8 +354,12 @@ class OperationsWaiter {
e.preventDefault();
e.stopPropagation();
const categoryId = e.target.dataset.category;
if (!categoryId) return;
// Bootstrap's popover sanitizer strips custom data-* attributes, so the
// category ID is derived from the link text using the same scheme as
// HTMLCategory.toHtml()
const catName = e.target.textContent;
if (!catName) return;
const categoryId = "cat" + catName.replace(/[\s/\-:_]/g, "");
// Hide all popovers
$("[data-toggle=popover]").popover("hide");
@ -377,12 +381,15 @@ class OperationsWaiter {
}
}
// Close all categories and open the target one
$("#categories .collapse").collapse("hide");
$(`#${categoryId}`).collapse("show");
// Open the target category. The accordion behaviour (data-parent) closes
// any other open category automatically. Calling "show" on an already
// open category would toggle-close it mid-transition, so skip it.
const categoryElement = document.getElementById(categoryId);
if (categoryElement && !categoryElement.classList.contains("show")) {
$(categoryElement).collapse("show");
}
// Scroll the category into view
const categoryElement = document.getElementById(categoryId);
if (categoryElement) {
categoryElement.scrollIntoView({behavior: "smooth", block: "nearest"});
}