https://github.com/python/cpython/commit/adf0b94d1cdd74340c8bc031f7464d0a33200f08
commit: adf0b94d1cdd74340c8bc031f7464d0a33200f08
branch: main
author: Adam Turner <9087854+aa-tur...@users.noreply.github.com>
committer: AA-Turner <9087854+aa-tur...@users.noreply.github.com>
date: 2024-07-19T10:16:59+01:00
summary:

GH-121970: Improve the glossary preview in HTML search (#121991)

files:
A Doc/tools/static/glossary_search.js
M Doc/tools/extensions/glossary_search.py
M Doc/tools/templates/search.html

diff --git a/Doc/tools/extensions/glossary_search.py 
b/Doc/tools/extensions/glossary_search.py
index 7c93b1e4990603..2448529125cb1f 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 00000000000000..13d728dc027f1d
--- /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 852974461380f2..6ddac5f828bab1 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 %}

_______________________________________________
Python-checkins mailing list -- python-checkins@python.org
To unsubscribe send an email to python-checkins-le...@python.org
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: arch...@mail-archive.com

Reply via email to