-
Notifications
You must be signed in to change notification settings - Fork 29
feat(search): improve filename normalization for better auto results #414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
djdembeck
wants to merge
23
commits into
develop
Choose a base branch
from
feature/issue-159-search-string-cleanup
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 20 commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
9cb5557
feat(ui): add book counts to status tabs
djdembeck 3225d2e
fix(i18n): use pluralize filter for grammatical correctness in aria-l…
djdembeck 03f8c2c
fix(ui): prevent description text from being cut off
djdembeck 9fa10d8
feat(search): improve filename normalization for better auto results
djdembeck 4d0c1b0
feat(importer): improve template accessibility and CSS
djdembeck 79ab01f
fix(search): update regex patterns for narrator and year removal
djdembeck 2325908
fix(accessibility): add keyboard navigation for book tabs and fix emp…
djdembeck 156c4c3
Merge branch 'develop' into feature/issue-159-search-string-cleanup
djdembeck 01af28b
fix: accessibility and regex improvements
djdembeck 64a1cf1
fix(book_tabs): add defensive null checks and fix HTML attribute quoting
djdembeck c10cb28
feat(book_tabs): add keyboard navigation for tabs
djdembeck f8d3fbb
fix(book_tabs): add user-initiated flag to openTab and null-check tabId
djdembeck ecc29d3
fix(book_tabs): safer event handling and aria-controls fallback
djdembeck 4c1a8e4
fix(book_tabs): normalize tab IDs and fix aria-controls lookup
djdembeck d8d180b
fix(tabs): validate tab elements before clearing panes and add compre…
djdembeck 71f9724
fix(tabs): normalize tabId and refactor tests to use initializeTabs
djdembeck ed5607b
fix(book_tabs): guard against blank tab IDs and prevent duplicate key…
djdembeck 6385d30
fix: trim whitespace before stripping hash in tab ID normalization
djdembeck b1179fb
fix(book_tabs): add doc parameter to openTab and handleKeyDown for te…
djdembeck 0fdc124
fix(book_tabs): prevent duplicate warnings when data-default normaliz…
djdembeck 4daa75c
fix(book_tabs): refactor fallback tab resolution into helper, handle …
djdembeck 82bb534
fix(book_tabs): validate default tab exists and handle empty aria-con…
djdembeck 35760cc
fix(book_tabs): add defensive guard for event.preventDefault in handl…
djdembeck File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,148 @@ | ||
| function openTab(tabId) { | ||
| const tabLinks = document.querySelectorAll(".tab"); | ||
| function openTab(event, tabId, userInitiated = false, doc = document) { | ||
| if (event && typeof event.preventDefault === 'function') { | ||
| event.preventDefault(); | ||
| } | ||
|
|
||
| const normalizedId = tabId && tabId.toString().trim().replace(/^#/, ''); | ||
|
|
||
| if (!normalizedId) { | ||
| console.warn(`Tab ID is blank or whitespace-only: '${tabId}'`); | ||
| return; | ||
| } | ||
|
|
||
| const tabElem = doc.getElementById(normalizedId); | ||
| const tabButton = doc.getElementById(`${normalizedId}-tab`); | ||
| if (!tabElem) { | ||
| console.warn(`Tab element with id '${normalizedId}' not found`); | ||
| return; | ||
| } | ||
| if (!tabButton) { | ||
| console.warn(`Tab button with id '${normalizedId}-tab' not found`); | ||
| return; | ||
| } | ||
|
|
||
| const tabLinks = doc.querySelectorAll(".tab"); | ||
| tabLinks.forEach(tab => { | ||
| tab.classList.remove("is-active"); | ||
| }); | ||
|
|
||
| const tabPanes = document.querySelectorAll(".tab-pane"); | ||
| const tabPanes = doc.querySelectorAll(".tab-pane"); | ||
| tabPanes.forEach(pane => { | ||
| pane.style.display = "none"; | ||
| }); | ||
|
|
||
| document.getElementById(tabId).style.display = "block"; | ||
| document.getElementById(`${tabId}-tab`).classList.add("is-active"); | ||
| tabElem.style.display = "block"; | ||
| tabButton.classList.add("is-active"); | ||
|
|
||
| const tabAnchors = doc.querySelectorAll('.tab a[role="tab"]'); | ||
| tabAnchors.forEach(anchor => { | ||
| const anchorControls = anchor.getAttribute('aria-controls'); | ||
| const normalizedAnchorControls = anchorControls && anchorControls.trim().replace(/^#/, ''); | ||
| if (normalizedAnchorControls === normalizedId) { | ||
| anchor.setAttribute('aria-selected', 'true'); | ||
| anchor.setAttribute('tabindex', '0'); | ||
| if (userInitiated) { | ||
| anchor.focus(); | ||
| } | ||
| } else { | ||
| anchor.setAttribute('aria-selected', 'false'); | ||
| anchor.setAttribute('tabindex', '-1'); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| function handleKeyDown(event, doc = document) { | ||
| const tabAnchors = Array.from(doc.querySelectorAll('.tab a[role="tab"]')); | ||
| const currentIndex = tabAnchors.indexOf(doc.activeElement); | ||
|
|
||
| if (currentIndex === -1 || tabAnchors.length === 0) return; | ||
|
|
||
| let nextIndex = currentIndex; | ||
|
|
||
| switch (event.key) { | ||
| case 'ArrowLeft': | ||
| nextIndex = currentIndex > 0 ? currentIndex - 1 : tabAnchors.length - 1; | ||
| break; | ||
| case 'ArrowRight': | ||
| nextIndex = currentIndex < tabAnchors.length - 1 ? currentIndex + 1 : 0; | ||
| break; | ||
| case 'Home': | ||
| nextIndex = 0; | ||
| break; | ||
| case 'End': | ||
| nextIndex = tabAnchors.length - 1; | ||
| break; | ||
| default: | ||
| return; | ||
| } | ||
|
|
||
| event.preventDefault(); | ||
| const nextTab = tabAnchors[nextIndex]; | ||
| const tabIdRaw = nextTab.getAttribute('aria-controls'); | ||
| if (tabIdRaw) { | ||
| const tabId = tabIdRaw.trim().replace(/^#/, ""); | ||
| openTab({ preventDefault: () => {} }, tabId, true, doc); | ||
| } else { | ||
| console.warn(`Tab anchor at index ${nextIndex} missing aria-controls attribute`); | ||
| } | ||
| } | ||
|
|
||
| function initializeTabs(doc = document) { | ||
| const tabsContainer = doc.querySelector(".tabs"); | ||
| let defaultTab; | ||
|
|
||
| if (tabsContainer && tabsContainer.dataset.default) { | ||
| defaultTab = tabsContainer.dataset.default.trim().replace(/^#/, ""); | ||
| // Guard against blank or whitespace-only values after normalization | ||
| if (!defaultTab) { | ||
| console.warn("data-default normalized to empty, using fallback tab"); | ||
| } | ||
| } else if (!defaultTab) { | ||
| if (!tabsContainer) { | ||
| console.warn(".tabs container not found, using fallback tab"); | ||
| } else { | ||
| console.warn("data-default attribute missing or empty, using fallback tab"); | ||
| } | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| const firstTabButton = doc.querySelector(".tab"); | ||
| if (firstTabButton) { | ||
| let ariaControls = firstTabButton.getAttribute("aria-controls"); | ||
| if (!ariaControls) { | ||
| const anchorWithControls = firstTabButton.querySelector('[aria-controls]'); | ||
| if (anchorWithControls) { | ||
| ariaControls = anchorWithControls.getAttribute("aria-controls"); | ||
| } | ||
| } | ||
| if (ariaControls) { | ||
| defaultTab = ariaControls.trim().replace(/^#/, ""); | ||
| } else { | ||
| const parsed = firstTabButton.id.replace("-tab", ""); | ||
| defaultTab = parsed || "done"; | ||
| } | ||
| } else { | ||
| defaultTab = "done"; | ||
| } | ||
| } | ||
| openTab({ preventDefault: () => {} }, defaultTab, false, doc); | ||
|
|
||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
| const tabAnchors = doc.querySelectorAll('.tab a[role="tab"]'); | ||
| tabAnchors.forEach(anchor => { | ||
| if (!anchor.dataset.keydownBound) { | ||
| anchor.addEventListener('keydown', (e) => handleKeyDown(e, doc)); | ||
| anchor.dataset.keydownBound = 'true'; | ||
| } | ||
| }); | ||
|
coderabbitai[bot] marked this conversation as resolved.
|
||
|
|
||
| return defaultTab; | ||
| } | ||
|
|
||
| window.addEventListener('load', function () { | ||
| const defaultTab = document.querySelector(".tabs").dataset.default | ||
| openTab(defaultTab); | ||
| }); | ||
| // Browser-only initialization (skipped during Node.js testing) | ||
| if (typeof window !== 'undefined') { | ||
| window.addEventListener('load', function () { | ||
| initializeTabs(document); | ||
| }); | ||
| } | ||
|
|
||
| // Export for testing | ||
| if (typeof module !== 'undefined' && module.exports) { | ||
| module.exports = { openTab, handleKeyDown, initializeTabs }; | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.