fix: resolve tag autocomplete click bug and display name fallback
Tag autocomplete suggestions were silently broken by CSP (script-src 'self') which blocks inline event handlers. Replaced onclick attributes with data-tag-name + delegated mousedown/touchend listeners in app.js. Also changed hx-params="*" to hx-params="none" to avoid sending unrelated form fields to the search endpoint. Display name in "av <name>" on fave cards was empty for users without a custom display name. Changed SQL queries to use COALESCE(NULLIF(u.display_name, ''), u.username) for automatic fallback. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
0a77935d4d
commit
9c3ca14578
4 changed files with 29 additions and 9 deletions
|
|
@ -43,7 +43,7 @@ func (s *FaveStore) GetByID(id int64) (*model.Fave, error) {
|
|||
var createdAt, updatedAt string
|
||||
err := s.db.QueryRow(
|
||||
`SELECT f.id, f.user_id, f.description, f.url, f.image_path, f.privacy,
|
||||
f.created_at, f.updated_at, u.username, u.display_name
|
||||
f.created_at, f.updated_at, u.username, COALESCE(NULLIF(u.display_name, ''), u.username)
|
||||
FROM faves f
|
||||
JOIN users u ON u.id = f.user_id
|
||||
WHERE f.id = ?`, id,
|
||||
|
|
@ -97,7 +97,7 @@ func (s *FaveStore) ListByUser(userID int64, limit, offset int) ([]*model.Fave,
|
|||
|
||||
rows, err := s.db.Query(
|
||||
`SELECT f.id, f.user_id, f.description, f.url, f.image_path, f.privacy,
|
||||
f.created_at, f.updated_at, u.username, u.display_name
|
||||
f.created_at, f.updated_at, u.username, COALESCE(NULLIF(u.display_name, ''), u.username)
|
||||
FROM faves f
|
||||
JOIN users u ON u.id = f.user_id
|
||||
WHERE f.user_id = ?
|
||||
|
|
@ -126,7 +126,7 @@ func (s *FaveStore) ListPublicByUser(userID int64, limit, offset int) ([]*model.
|
|||
|
||||
rows, err := s.db.Query(
|
||||
`SELECT f.id, f.user_id, f.description, f.url, f.image_path, f.privacy,
|
||||
f.created_at, f.updated_at, u.username, u.display_name
|
||||
f.created_at, f.updated_at, u.username, COALESCE(NULLIF(u.display_name, ''), u.username)
|
||||
FROM faves f
|
||||
JOIN users u ON u.id = f.user_id
|
||||
WHERE f.user_id = ? AND f.privacy = 'public'
|
||||
|
|
@ -153,7 +153,7 @@ func (s *FaveStore) ListPublic(limit, offset int) ([]*model.Fave, int, error) {
|
|||
|
||||
rows, err := s.db.Query(
|
||||
`SELECT f.id, f.user_id, f.description, f.url, f.image_path, f.privacy,
|
||||
f.created_at, f.updated_at, u.username, u.display_name
|
||||
f.created_at, f.updated_at, u.username, COALESCE(NULLIF(u.display_name, ''), u.username)
|
||||
FROM faves f
|
||||
JOIN users u ON u.id = f.user_id
|
||||
WHERE f.privacy = 'public'
|
||||
|
|
@ -185,7 +185,7 @@ func (s *FaveStore) ListByTag(tagName string, limit, offset int) ([]*model.Fave,
|
|||
|
||||
rows, err := s.db.Query(
|
||||
`SELECT f.id, f.user_id, f.description, f.url, f.image_path, f.privacy,
|
||||
f.created_at, f.updated_at, u.username, u.display_name
|
||||
f.created_at, f.updated_at, u.username, COALESCE(NULLIF(u.display_name, ''), u.username)
|
||||
FROM faves f
|
||||
JOIN users u ON u.id = f.user_id
|
||||
JOIN fave_tags ft ON ft.fave_id = f.id
|
||||
|
|
|
|||
|
|
@ -70,6 +70,26 @@
|
|||
// --- Tag autocomplete combobox pattern ---
|
||||
var activeIndex = -1;
|
||||
|
||||
// Delegated event handler for tag suggestion selection.
|
||||
// Uses mousedown (not click) to fire before blur removes the element.
|
||||
// Uses touchend for mobile support. Both prevent default to keep
|
||||
// the tags input focused. Inline handlers (onclick/onmousedown) are
|
||||
// blocked by CSP script-src 'self', so we must use addEventListener.
|
||||
document.addEventListener("mousedown", function (event) {
|
||||
var li = event.target.closest("[data-tag-name]");
|
||||
if (li) {
|
||||
event.preventDefault();
|
||||
addTag(null, li.getAttribute("data-tag-name"));
|
||||
}
|
||||
});
|
||||
document.addEventListener("touchend", function (event) {
|
||||
var li = event.target.closest("[data-tag-name]");
|
||||
if (li) {
|
||||
event.preventDefault();
|
||||
addTag(null, li.getAttribute("data-tag-name"));
|
||||
}
|
||||
});
|
||||
|
||||
// Handle keyboard navigation in the tag suggestions listbox.
|
||||
document.addEventListener("keydown", function (event) {
|
||||
var input = document.getElementById("tags");
|
||||
|
|
@ -152,7 +172,7 @@
|
|||
}
|
||||
|
||||
// Add a selected tag to the tag input.
|
||||
window.addTag = function (element, tagName) {
|
||||
function addTag(element, tagName) {
|
||||
var input = document.getElementById("tags");
|
||||
if (!input) return;
|
||||
|
||||
|
|
@ -162,7 +182,7 @@
|
|||
input.focus();
|
||||
|
||||
closeSuggestions();
|
||||
};
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
var match = document.cookie.match(new RegExp("(^| )" + name + "=([^;]+)"));
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@
|
|||
hx-get="{{basePath}}/tags/search"
|
||||
hx-trigger="keyup changed delay:300ms"
|
||||
hx-target="#tag-suggestions"
|
||||
hx-params="*"
|
||||
hx-params="none"
|
||||
hx-vals='{"q": ""}'>
|
||||
<small id="tags-help">Skriv for å søke i eksisterende merkelapper. Maks {{maxTags}} stk. Bruk piltaster for å velge.</small>
|
||||
</label>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,6 @@
|
|||
id="tag-option-{{$i}}"
|
||||
class="tag-suggestion"
|
||||
aria-selected="false"
|
||||
onclick="addTag(this, '{{$tag.Name}}')"
|
||||
data-tag-name="{{$tag.Name}}"
|
||||
tabindex="-1">{{$tag.Name}}</li>
|
||||
{{end}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue