diff options
author | Adam Turner <9087854+AA-Turner@users.noreply.github.com> | 2024-07-19 09:16:59 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-07-19 09:16:59 (GMT) |
commit | adf0b94d1cdd74340c8bc031f7464d0a33200f08 (patch) | |
tree | 624e4a60a69c33c383796fb6eff1ce0768e67f5f | |
parent | 1a0c7b9ba48a2dffb70bb0c7327abae1d3e87356 (diff) | |
download | cpython-adf0b94d1cdd74340c8bc031f7464d0a33200f08.zip cpython-adf0b94d1cdd74340c8bc031f7464d0a33200f08.tar.gz cpython-adf0b94d1cdd74340c8bc031f7464d0a33200f08.tar.bz2 |
GH-121970: Improve the glossary preview in HTML search (#121991)
-rw-r--r-- | Doc/tools/extensions/glossary_search.py | 68 | ||||
-rw-r--r-- | Doc/tools/static/glossary_search.js | 47 | ||||
-rw-r--r-- | Doc/tools/templates/search.html | 69 |
3 files changed, 91 insertions, 93 deletions
diff --git a/Doc/tools/extensions/glossary_search.py b/Doc/tools/extensions/glossary_search.py index 7c93b1e..2448529 100644 --- a/Doc/tools/extensions/glossary_search.py +++ b/Doc/tools/extensions/glossary_search.py @@ -1,63 +1,59 @@ -# -*- coding: utf-8 -*- -""" - glossary_search.py - ~~~~~~~~~~~~~~~~ +"""Feature search results for glossary items prominently.""" - Feature search results for glossary items prominently. +from __future__ import annotations - :license: Python license. -""" import json -import os.path -from docutils.nodes import definition_list_item +from pathlib import Path +from typing import TYPE_CHECKING + +from docutils import nodes from sphinx.addnodes import glossary from sphinx.util import logging +if TYPE_CHECKING: + from sphinx.application import Sphinx + from sphinx.util.typing import ExtensionMetadata logger = logging.getLogger(__name__) -STATIC_DIR = '_static' -JSON = 'glossary.json' -def process_glossary_nodes(app, doctree, fromdocname): +def process_glossary_nodes(app: Sphinx, doctree: nodes.document, _docname: str) -> None: if app.builder.format != 'html' or app.builder.embedded: return - terms = {} + if hasattr(app.env, 'glossary_terms'): + terms = app.env.glossary_terms + else: + terms = app.env.glossary_terms = {} for node in doctree.findall(glossary): - for glossary_item in node.findall(definition_list_item): - term = glossary_item[0].astext().lower() - definition = glossary_item[1] + for glossary_item in node.findall(nodes.definition_list_item): + term = glossary_item[0].astext() + definition = glossary_item[-1] rendered = app.builder.render_partial(definition) - terms[term] = { - 'title': glossary_item[0].astext(), + terms[term.lower()] = { + 'title': term, 'body': rendered['html_body'] } - if hasattr(app.env, 'glossary_terms'): - app.env.glossary_terms.update(terms) - else: - app.env.glossary_terms = terms -def on_build_finish(app, exc): - if not hasattr(app.env, 'glossary_terms'): - return - if not app.env.glossary_terms: +def write_glossary_json(app: Sphinx, _exc: Exception) -> None: + if not getattr(app.env, 'glossary_terms', None): return - logger.info(f'Writing {JSON}', color='green') - - dest_dir = os.path.join(app.outdir, STATIC_DIR) - os.makedirs(dest_dir, exist_ok=True) - - with open(os.path.join(dest_dir, JSON), 'w') as f: - json.dump(app.env.glossary_terms, f) + logger.info(f'Writing glossary.json', color='green') + dest = Path(app.outdir, '_static', 'glossary.json') + dest.parent.mkdir(exist_ok=True) + dest.write_text(json.dumps(app.env.glossary_terms), encoding='utf-8') -def setup(app): +def setup(app: Sphinx) -> ExtensionMetadata: app.connect('doctree-resolved', process_glossary_nodes) - app.connect('build-finished', on_build_finish) + app.connect('build-finished', write_glossary_json) - return {'version': '0.1', 'parallel_read_safe': True} + return { + 'version': '1.0', + 'parallel_read_safe': True, + 'parallel_write_safe': True, + } diff --git a/Doc/tools/static/glossary_search.js b/Doc/tools/static/glossary_search.js new file mode 100644 index 0000000..13d728d --- /dev/null +++ b/Doc/tools/static/glossary_search.js @@ -0,0 +1,47 @@ +"use strict"; + +const GLOSSARY_PAGE = "glossary.html"; + +const glossary_search = async () => { + const response = await fetch("_static/glossary.json"); + if (!response.ok) { + throw new Error("Failed to fetch glossary.json"); + } + const glossary = await response.json(); + + const params = new URLSearchParams(document.location.search).get("q"); + if (!params) { + return; + } + + const searchParam = params.toLowerCase(); + const glossaryItem = glossary[searchParam]; + if (!glossaryItem) { + return; + } + + // set up the title text with a link to the glossary page + const glossaryTitle = document.getElementById("glossary-title"); + glossaryTitle.textContent = "Glossary: " + glossaryItem.title; + const linkTarget = searchParam.replace(/ /g, "-"); + glossaryTitle.href = GLOSSARY_PAGE + "#term-" + linkTarget; + + // rewrite any anchor links (to other glossary terms) + // to have a full reference to the glossary page + const glossaryBody = document.getElementById("glossary-body"); + glossaryBody.innerHTML = glossaryItem.body; + const anchorLinks = glossaryBody.querySelectorAll('a[href^="#"]'); + anchorLinks.forEach(function (link) { + const currentUrl = link.getAttribute("href"); + link.href = GLOSSARY_PAGE + currentUrl; + }); + + const glossaryResult = document.getElementById("glossary-result"); + glossaryResult.style.display = ""; +}; + +if (document.readyState !== "loading") { + glossary_search().catch(console.error); +} else { + document.addEventListener("DOMContentLoaded", glossary_search); +} diff --git a/Doc/tools/templates/search.html b/Doc/tools/templates/search.html index 8529744..6ddac5f 100644 --- a/Doc/tools/templates/search.html +++ b/Doc/tools/templates/search.html @@ -2,61 +2,16 @@ {% block extrahead %} {{ super() }} <meta name="robots" content="noindex"> - <script type="text/javascript"> - const GLOSSARY_PAGE = 'glossary.html'; - - document.addEventListener('DOMContentLoaded', function() { - fetch('_static/glossary.json') - .then(function(response) { - if (response.ok) { - return response.json(); - } else { - throw new Error('Failed to fetch glossary.json'); - } - }) - .then(function(glossary) { - const RESULT_TEMPLATE = '<div style="display: none" class="admonition seealso" id="glossary-result">' + - ' <p class="topic-title">' + - ' <a class="glossary-title" href="#"></a>' + - ' </p>' + - ' <div class="glossary-body"></div>' + - '</div>'; - let searchResults = document.getElementById('search-results'); - searchResults.insertAdjacentHTML('afterbegin', RESULT_TEMPLATE); - - const params = new URLSearchParams(document.location.search).get("q"); - if (params) { - const searchParam = params.toLowerCase(); - const glossaryItem = glossary[searchParam]; - if (glossaryItem) { - let resultDiv = document.getElementById('glossary-result'); - - // set up the title text with a link to the glossary page - let glossaryTitle = resultDiv.querySelector('.glossary-title'); - glossaryTitle.textContent = 'Glossary: ' + glossaryItem.title; - const linkTarget = searchParam.replace(/ /g, '-'); - glossaryTitle.href = GLOSSARY_PAGE + '#term-' + linkTarget; - - // rewrite any anchor links (to other glossary terms) - // to have a full reference to the glossary page - let body = document.createElement('div'); - body.innerHTML = glossaryItem.body; - const anchorLinks = body.querySelectorAll('a[href^="#"]'); - anchorLinks.forEach(function(link) { - const currentUrl = link.getAttribute('href'); - link.href = GLOSSARY_PAGE + currentUrl; - }); - resultDiv.querySelector('.glossary-body').appendChild(body); - - resultDiv.style.display = ''; - } else { - document.getElementById('glossary-result').style.display = 'none'; - } - } - }) - .catch(function(error) { - console.error(error); - }); - }); - </script> + <script type="text/javascript" src="{{ pathto('_static/glossary_search.js', resource=True) }}"></script> +{% endblock %} +{% block searchresults %} +<div id="search-results"> + {# For glossary_search.js #} + <div style="display: none;" class="admonition seealso" id="glossary-result"> + <p class="topic-title"> + <a id="glossary-title" href="#"></a> + </p> + <div id="glossary-body"></div> +</div> +</div> {% endblock %} |