Skip to content

Commit 6ecfa35

Browse files
fix: remove duplicate search results for same parent page (#1464)
1 parent 8bd4887 commit 6ecfa35

File tree

1 file changed

+92
-4
lines changed

1 file changed

+92
-4
lines changed

antora-ui-camel/src/js/vendor/algoliasearch.bundle.js

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,91 @@
6868
})
6969
}
7070

71+
// Extract the parent page path from a URL (removes anchor and trailing segments)
72+
function getParentPagePath (url) {
73+
if (!url) return ''
74+
// Remove anchor fragment
75+
var path = url.split('#')[0]
76+
// Normalize trailing slash
77+
if (path.endsWith('/')) {
78+
path = path.slice(0, -1)
79+
}
80+
return path
81+
}
82+
83+
// Check if hit represents a sub-section of a page (has anchor or deeper hierarchy)
84+
function isSubSection (hit) {
85+
if (!hit || !hit.url) return false
86+
return hit.url.indexOf('#') !== -1
87+
}
88+
89+
// Get the breadcrumb depth (number of hierarchy levels)
90+
function getBreadcrumbDepth (hit) {
91+
if (!hit || !hit.hierarchy) return 0
92+
return Object.values(hit.hierarchy).filter(function (lvl) {
93+
return lvl !== null
94+
}).length
95+
}
96+
97+
// Remove duplicate results for the same parent page
98+
// When parent page is a direct match, exclude its sub-sections
99+
function deduplicateHits (hits, query) {
100+
var seenPages = {}
101+
var parentMatches = {}
102+
var queryLower = (query || '').toLowerCase().trim()
103+
104+
// First pass: identify parent pages that match the query directly
105+
hits.forEach(function (hit) {
106+
var parentPath = getParentPagePath(hit.url)
107+
var hierarchy = hit.hierarchy || {}
108+
109+
// Check if any top-level hierarchy matches the search query
110+
var lvl1 = (hierarchy.lvl1 || '').toLowerCase()
111+
var lvl0 = (hierarchy.lvl0 || '').toLowerCase()
112+
113+
if (lvl1 && lvl1.indexOf(queryLower) !== -1) {
114+
parentMatches[parentPath] = true
115+
}
116+
if (lvl0 && lvl0.indexOf(queryLower) !== -1) {
117+
parentMatches[parentPath] = true
118+
}
119+
})
120+
121+
// Second pass: filter out sub-sections when parent is already matched
122+
return hits.filter(function (hit) {
123+
var parentPath = getParentPagePath(hit.url)
124+
var isSubSec = isSubSection(hit)
125+
var depth = getBreadcrumbDepth(hit)
126+
127+
// If this is a sub-section and parent page already matched, skip it
128+
if (isSubSec && parentMatches[parentPath]) {
129+
// Only keep the main page hit, not sub-sections
130+
if (seenPages[parentPath]) {
131+
return false
132+
}
133+
}
134+
135+
// For component pages, only show the main entry (depth <= 2)
136+
if (isComponentUrl(hit.url) && depth > 2 && seenPages[parentPath]) {
137+
return false
138+
}
139+
140+
// Track that we've seen this parent page
141+
if (!seenPages[parentPath]) {
142+
seenPages[parentPath] = { depth: depth, hit: hit }
143+
return true
144+
}
145+
146+
// If we already have this page, only keep if it's a better match (shallower)
147+
if (depth < seenPages[parentPath].depth) {
148+
seenPages[parentPath] = { depth: depth, hit: hit }
149+
return true
150+
}
151+
152+
return false
153+
})
154+
}
155+
71156
function truncateHighlightedHtml (html, maxChars) {
72157
if (!html || maxChars <= 0) return ''
73158

@@ -170,17 +255,20 @@
170255
return
171256
}
172257
cancel.style.display = 'block'
258+
var searchQuery = search.value
173259
index
174-
.search(search.value, {
175-
hitsPerPage: 20,
260+
.search(searchQuery, {
261+
hitsPerPage: 50,
176262
})
177263
.then((results) => {
178264
// Filter out sub-project results to focus on camel-core documentation
179265
const filteredHits = results.hits.filter(function (hit) {
180266
return !isSubProjectUrl(hit.url)
181267
})
182-
// Sort to prioritize core docs over components
183-
const sortedHits = sortByCoreDocs(filteredHits).slice(0, RESULTS_LIMIT)
268+
// Remove duplicate results for the same parent page
269+
const dedupedHits = deduplicateHits(filteredHits, searchQuery)
270+
// Sort to prioritize core docs over components and limit results
271+
const sortedHits = sortByCoreDocs(dedupedHits).slice(0, RESULTS_LIMIT)
184272
const data = sortedHits.reduce((data, hit) => {
185273
const section = hit.hierarchy.lvl0
186274
const sectionKey = `${section}-${hit.version || ''}`

0 commit comments

Comments
 (0)