Skip to content

Commit

Permalink
Close #6241: html: Allow to add JS/CSS files to the specific page
Browse files Browse the repository at this point in the history
Allow to add JS/CSS files to the specific page when an extension calls
`app.add_js_file()` or `app.add_css_file()` on `html-page-context`
event.
  • Loading branch information
tk0miya committed Jan 4, 2021
1 parent ac7d574 commit edb5a55
Show file tree
Hide file tree
Showing 9 changed files with 48 additions and 13 deletions.
4 changes: 4 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,12 @@ Features added
* #8619: html: kbd role generates customizable HTML tags for compound keys
* #8634: html: Allow to change the order of JS/CSS via ``priority`` parameter
for :meth:`Sphinx.add_js_file()` and :meth:`Sphinx.add_css_file()`
* #6241: html: Allow to add JS/CSS files to the specific page when an extension
calls ``app.add_js_file()`` or ``app.add_css_file()`` on
:event:`html-page-context` event
* #8649: imgconverter: Skip availability check if builder supports the image
type
* #6241: mathjax: Include mathjax.js only on the document using equations
* #8132: Add :confval:`project_copyright` as an alias of :confval:`copyright`

Bugs fixed
Expand Down
3 changes: 3 additions & 0 deletions doc/extdev/appapi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,9 @@ Here is a more detailed list of these events.
You can return a string from the handler, it will then replace
``'page.html'`` as the HTML template for this page.

.. note:: You can install JS/CSS files for the specific page via
:meth:`Sphinx.add_js_file` and :meth:`Sphinx.add_css_file` since v4.0.

.. versionadded:: 0.4

.. versionchanged:: 1.3
Expand Down
9 changes: 7 additions & 2 deletions sphinx/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -965,7 +965,10 @@ def add_js_file(self, filename: str, priority: int = 500, **kwargs: Any) -> None
And it allows keyword arguments as attributes of script tag.
.. versionchanged:: 3.5
Take priority argument.
* Take priority argument.
* Allowed to add a JavaScript file to the specific HTML page when an
extension calls this on :event:`html-page-context` event.
"""
self.registry.add_js_file(filename, priority=priority, **kwargs)
if hasattr(self.builder, 'add_js_file'):
Expand Down Expand Up @@ -1018,7 +1021,9 @@ def add_css_file(self, filename: str, priority: int = 500, **kwargs: Any) -> Non
And it allows keyword arguments as attributes of link tag.
.. versionchanged:: 3.5
Take priority argument.
* Take priority argument.
* Allowed to add a stylesheet file to the specific HTML page when an
extension calls this on :event:`html-page-context` event.
"""
logger.debug('[app] adding stylesheet: %r', filename)
self.registry.add_css_files(filename, priority=priority, **kwargs)
Expand Down
8 changes: 8 additions & 0 deletions sphinx/builders/html/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,10 @@ def prepare_writing(self, docnames: Set[str]) -> None:
rellinks.append((indexname, indexcls.localname,
'', indexcls.shortname))

# back up script_files and css_files to allow adding JS/CSS files to a specific page.
self._script_files = list(self.script_files)
self._css_files = list(self.css_files)

if self.config.html_style is not None:
stylename = self.config.html_style
elif self.theme:
Expand Down Expand Up @@ -1016,6 +1020,10 @@ def hasdoc(name: str) -> bool:
self.add_sidebars(pagename, ctx)
ctx.update(addctx)

# revert script_files and css_files
self.script_files[:] = self._script_files
self.css_files[:] = self.css_files

self.update_page_context(pagename, templatename, ctx, event_arg)
newtmpl = self.app.emit_firstresult('html-page-context', pagename,
templatename, ctx, event_arg)
Expand Down
7 changes: 5 additions & 2 deletions sphinx/domains/math.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,11 @@ def get_next_equation_number(self, docname: str) -> int:
targets = [eq for eq in self.equations.values() if eq[0] == docname]
return len(targets) + 1

def has_equations(self) -> bool:
return any(self.data['has_equations'].values())
def has_equations(self, docname: str = None) -> bool:
if docname:
return self.data['has_equations'].get(docname, False)
else:
return any(self.data['has_equations'].values())


def setup(app: "Sphinx") -> Dict[str, Any]:
Expand Down
16 changes: 7 additions & 9 deletions sphinx/ext/mathjax.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@

import sphinx
from sphinx.application import Sphinx
from sphinx.builders.html import StandaloneHTMLBuilder
from sphinx.domains.math import MathDomain
from sphinx.environment import BuildEnvironment
from sphinx.errors import ExtensionError
from sphinx.locale import _
from sphinx.util.math import get_node_equation_number
Expand Down Expand Up @@ -71,25 +69,25 @@ def html_visit_displaymath(self: HTMLTranslator, node: nodes.math_block) -> None
raise nodes.SkipNode


def install_mathjax(app: Sphinx, env: BuildEnvironment) -> None:
def install_mathjax(app: Sphinx, pagename: str, templatename: str, context: Dict,
event_arg: Any) -> None:
if app.builder.format != 'html' or app.builder.math_renderer_name != 'mathjax': # type: ignore # NOQA
return
if not app.config.mathjax_path:
raise ExtensionError('mathjax_path config value must be set for the '
'mathjax extension to work')

builder = cast(StandaloneHTMLBuilder, app.builder)
domain = cast(MathDomain, env.get_domain('math'))
if domain.has_equations():
domain = cast(MathDomain, app.env.get_domain('math'))
if domain.has_equations(pagename):
# Enable mathjax only if equations exists
options = {'async': 'async'}
if app.config.mathjax_options:
options.update(app.config.mathjax_options)
builder.add_js_file(app.config.mathjax_path, **options)
app.add_js_file(app.config.mathjax_path, **options) # type: ignore

if app.config.mathjax_config:
body = "MathJax.Hub.Config(%s)" % json.dumps(app.config.mathjax_config)
builder.add_js_file(None, type="text/x-mathjax-config", body=body)
app.add_js_file(None, type="text/x-mathjax-config", body=body)


def setup(app: Sphinx) -> Dict[str, Any]:
Expand All @@ -102,6 +100,6 @@ def setup(app: Sphinx) -> Dict[str, Any]:
app.add_config_value('mathjax_inline', [r'\(', r'\)'], 'html')
app.add_config_value('mathjax_display', [r'\[', r'\]'], 'html')
app.add_config_value('mathjax_config', None, 'html')
app.connect('env-updated', install_mathjax)
app.connect('html-page-context', install_mathjax)

return {'version': sphinx.__display_version__, 'parallel_read_safe': True}
1 change: 1 addition & 0 deletions tests/roots/test-ext-math/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Test Math

math
page
nomath

.. math:: a^2+b^2=c^2

Expand Down
Empty file.
13 changes: 13 additions & 0 deletions tests/test_ext_math.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import pytest
from docutils import nodes

from sphinx.ext.mathjax import MATHJAX_URL
from sphinx.testing.util import assert_node


Expand Down Expand Up @@ -224,6 +225,18 @@ def test_mathjax_config(app, status, warning):
'</script>' in content)


@pytest.mark.sphinx('html', testroot='ext-math',
confoverrides={'extensions': ['sphinx.ext.mathjax']})
def test_mathjax_is_installed_only_if_document_having_math(app, status, warning):
app.builder.build_all()

content = (app.outdir / 'index.html').read_text()
assert MATHJAX_URL in content

content = (app.outdir / 'nomath.html').read_text()
assert MATHJAX_URL not in content


@pytest.mark.sphinx('html', testroot='basic',
confoverrides={'extensions': ['sphinx.ext.mathjax']})
def test_mathjax_is_not_installed_if_no_equations(app, status, warning):
Expand Down

0 comments on commit edb5a55

Please sign in to comment.