Skip to content

Commit

Permalink
docs: Fix inline search results URLs
Browse files Browse the repository at this point in the history
Bug: 365179592
Change-Id: I3bf5a26c8179a0ea57475d5ef08d0d31e09cfa39
Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/234551
Commit-Queue: Kayce Basques <[email protected]>
Presubmit-Verified: CQ Bot Account <[email protected]>
Lint: Lint 🤖 <[email protected]>
Reviewed-by: Anthony DiGirolamo <[email protected]>
  • Loading branch information
Kayce Basques authored and CQ Bot Account committed Sep 9, 2024
1 parent dbda5bd commit 93de076
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 13 deletions.
71 changes: 58 additions & 13 deletions docs/_static/js/pigweed.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,36 @@ window.pw = {};

// Display inline search results under the search modal. After the user types
// text in the search box, results are shown underneath the text input box.
// The search is restarted anew after each keypress.
// The search is restarted after each keypress.
//
// TODO: b/363034219 - Try to upstream this code into pydata-sphinx-theme.
window.pw.initSearch = () => {
// The search page has its own UI for running searches and displaying
// results. This logic isn't needed on /search.html.
// Don't interfere with the default search UX on /search.html.
if (window.location.pathname.endsWith('/search.html')) {
return;
}
// Search class is provided by Sphinx's built-in search tools.
// The template //docs/layout/page.html ensures that Sphinx's
// search scripts are always loaded before pigweed.js.
// The template //docs/layout/page.html ensures that Search is always
// loaded at this point.
// eslint-disable-next-line no-undef
if (!Search) {
return;
}
// Destroy the previous search container and create a new one.
window.pw.resetSearchResults();
let timeoutId = null;
let lastQuery = '';
const searchInput = document.querySelector('#search-input');
// Kick off the search after the user types something.
// Set up the event handler to initiate searches whenever the user
// types stuff in the search modal textbox.
searchInput.addEventListener('keyup', () => {
const query = searchInput.value;
// Don't search when there's nothing in the query text box.
// Don't search when there's nothing in the query textbox.
if (query === '') {
return;
}
// Don't search if there is no detectable change between
// the last query and the current query. This prevents the
// search from re-running if the user presses Tab to start
// navigating the search results.
// the last query and the current query. E.g. user presses
// Tab to start navigating the search results.
if (query === lastQuery) {
return;
}
Expand All @@ -69,6 +68,10 @@ window.pw.initSearch = () => {

// Resets the custom search results container to an empty state.
//
// Note that Sphinx assumes that searches are always made from /search.html
// so there's some safeguard logic to make sure the inline search always
// works no matter what pigweed.dev page you're on. b/365179592
//
// TODO: b/363034219 - Try to upstream this code into pydata-sphinx-theme.
window.pw.resetSearchResults = () => {
let results = document.querySelector('#search-results');
Expand All @@ -78,8 +81,50 @@ window.pw.resetSearchResults = () => {
results = document.createElement('section');
results.classList.add('pw-search-results');
results.id = 'search-results';
let container = document.querySelector('.search-button__search-container');
container.appendChild(results);
// The template //docs/layout/page.html ensures that DOCUMENTATION_OPTIONS
// is always loaded at this point.
// eslint-disable-next-line no-undef
if (!DOCUMENTATION_OPTIONS || !DOCUMENTATION_OPTIONS.URL_ROOT) {
return;
}
// eslint-disable-next-line no-undef
const urlRoot = DOCUMENTATION_OPTIONS.URL_ROOT;
// As Sphinx populates the search results, this observer makes sure that
// each URL is correct (i.e. doesn't 404). b/365179592
const linkObserver = new MutationObserver(() => {
const links = Array.from(
document.querySelectorAll('#search-results .search a'),
);
// Check every link every time because the timing of when new results are
// added is unpredictable and it's not an expensive operation.
links.forEach((link) => {
// Don't use the link.href getter because the browser computes the href
// as a full URL. We need the relative URL that Sphinx generates.
const href = link.getAttribute('href');
if (!href.startsWith(urlRoot)) {
link.href = `${urlRoot}${href}`;
}
});
});
// The node that linkObserver watches doesn't exist until the user types
// something into the search textbox. The next observer just waits for
// that node to exist and then registers linkObserver on it.
let isObserved = false;
const resultsObserver = new MutationObserver(() => {
if (isObserved) {
return;
}
const container = document.querySelector('#search-results .search');
if (!container) {
return;
}
linkObserver.observe(container, { childList: true });
isObserved = true;
});
resultsObserver.observe(results, { childList: true });
// Add the new nodes to the DOM.
let modal = document.querySelector('.search-button__search-container');
modal.appendChild(results);
};

window.addEventListener('DOMContentLoaded', () => {
Expand Down
1 change: 1 addition & 0 deletions docs/layout/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
{% else %}
{# Load Sphinx's built-in search tools so that our custom inline search
experience can work on any page. See //docs/_static/js/pigweed.js #}
<script src="{{ pathto('_static/documentation_options.js', 1) | e }}"></script>
<script src="{{ pathto('_static/searchtools.js', 1) | e }}"></script>
<script src="{{ pathto('_static/language_data.js', 1) | e }}"></script>
<script src="{{ pathto('searchindex.js', 1) | e }}"></script>
Expand Down

0 comments on commit 93de076

Please sign in to comment.