diff options
| author | Claude <noreply@anthropic.com> | 2026-02-28 22:53:24 +0000 |
|---|---|---|
| committer | Claude <noreply@anthropic.com> | 2026-02-28 22:53:24 +0000 |
| commit | df5e7d93963f0256285b13ddf750761930797e78 (patch) | |
| tree | 020cbd30711b1ee7eea3d077389ec381eded4a4e /frontend-vanilla/src/main.ts | |
| parent | 15aa629972c4bd9fd3ab5ddb442783483f57a61f (diff) | |
| download | neko-df5e7d93963f0256285b13ddf750761930797e78.tar.gz neko-df5e7d93963f0256285b13ddf750761930797e78.tar.bz2 neko-df5e7d93963f0256285b13ddf750761930797e78.zip | |
Fix star/read buttons: _id string vs number type mismatchclaude/agents-file-mobile-stars-2nj6y
The Go API returns _id as a JSON string (due to the `json:",string"` tag
on Item.Id), but the frontend compared it with === against numbers from
parseInt(). String "5" === number 5 is always false in JS, so toggleStar,
mark-as-read, and keyboard shortcuts silently did nothing.
Fix:
- Coerce _id to Number() when items are loaded from the API
- Use Number() coercion in all store.items.find() comparisons as defense
- Revert the CSS touch-target changes (the issue was never about size)
- Add a regression test with string _id to prevent reintroduction
https://claude.ai/code/session_012CNdRhGhU3hxjrwvZt2BHZ
Diffstat (limited to 'frontend-vanilla/src/main.ts')
| -rw-r--r-- | frontend-vanilla/src/main.ts | 19 |
1 files changed, 12 insertions, 7 deletions
diff --git a/frontend-vanilla/src/main.ts b/frontend-vanilla/src/main.ts index b59d185..5d67515 100644 --- a/frontend-vanilla/src/main.ts +++ b/frontend-vanilla/src/main.ts @@ -258,7 +258,7 @@ export function attachLayoutListeners() { const id = parseInt(itemRow.getAttribute('data-id')!); activeItemId = id; - const item = store.items.find(i => i._id === id); + const item = store.items.find(i => Number(i._id) === Number(id)); if (item && !item.read) { updateItem(id, { read: true }); } @@ -361,7 +361,7 @@ function checkReadItems(scrollRoot?: HTMLElement) { const id = parseInt(idAttr); // Safety check: skip if store already says it's read (though unread class implies not) - const item = store.items.find(i => i._id === id); + const item = store.items.find(i => Number(i._id) === Number(id)); if (item?.read) continue; const rect = el.getBoundingClientRect(); @@ -674,14 +674,14 @@ export async function updateFeed(id: number, updates: Partial<Feed>): Promise<bo // --- Data Actions --- export async function toggleStar(id: number) { - const item = store.items.find(i => i._id === id); + const item = store.items.find(i => Number(i._id) === Number(id)); if (item) { updateItem(id, { starred: !item.starred }); } } export async function scrapeItem(id: number) { - const item = store.items.find(i => i._id === id); + const item = store.items.find(i => Number(i._id) === Number(id)); if (!item) return; try { @@ -775,6 +775,11 @@ export async function fetchItems(feedId?: string, tagName?: string, append: bool const res = await apiFetch(`/api/stream?${params.toString()}`); if (res.ok) { const items = await res.json(); + // The Go API returns _id as a string (json:",string" tag). Coerce to + // number so DOM parseInt comparisons using === work everywhere. + for (const item of items) { + item._id = Number(item._id); + } store.setHasMore(items.length > 0); store.setItems(items, append); } @@ -840,13 +845,13 @@ window.addEventListener('keydown', (e) => { break; case 'r': if (activeItemId) { - const item = store.items.find(i => i._id === activeItemId); + const item = store.items.find(i => Number(i._id) === Number(activeItemId)); if (item) updateItem(item._id, { read: !item.read }); } break; case 's': if (activeItemId) { - const item = store.items.find(i => i._id === activeItemId); + const item = store.items.find(i => Number(i._id) === Number(activeItemId)); if (item) updateItem(item._id, { starred: !item.starred }); } break; @@ -859,7 +864,7 @@ window.addEventListener('keydown', (e) => { function navigateItems(direction: number) { if (store.items.length === 0) return; - const currentIndex = store.items.findIndex(i => i._id === activeItemId); + const currentIndex = store.items.findIndex(i => Number(i._id) === Number(activeItemId)); let nextIndex; if (currentIndex === -1) { |
