summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAdam Turner <9087854+AA-Turner@users.noreply.github.com>2024-07-19 09:16:59 (GMT)
committerGitHub <noreply@github.com>2024-07-19 09:16:59 (GMT)
commitadf0b94d1cdd74340c8bc031f7464d0a33200f08 (patch)
tree624e4a60a69c33c383796fb6eff1ce0768e67f5f
parent1a0c7b9ba48a2dffb70bb0c7327abae1d3e87356 (diff)
downloadcpython-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.py68
-rw-r--r--Doc/tools/static/glossary_search.js47
-rw-r--r--Doc/tools/templates/search.html69
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 %}