diff --git a/docs/configure.md b/docs/configure.md index 433400d..875d869 100644 --- a/docs/configure.md +++ b/docs/configure.md @@ -173,7 +173,7 @@ By default, Thebe encourages users to use the `thebe-button` directive to insert a thebe button into their documentation. However, you can add your own buttons wherever you wish. Simply ensure that an HTML element has this attribute: -``` +```js onclick="initThebe()" ``` @@ -193,7 +193,7 @@ directive: You can customize `sphinx-thebe` to use the codemirror theme of your choice. To do so, use the following configuration: -``` +```python thebe_config = { "codemirror-theme": "" } @@ -202,6 +202,17 @@ thebe_config = { See [the CodeMirror theme demo](https://codemirror.net/demo/theme.html) for a list of themes that you can use, and what they look like. +## Only load JS on certain pages + +By default, `sphinx-thebe` will load the JS/CSS from `thebe` on all of your documentation's pages. +Alternatively, you may load `thebe` only on pages that use the `thebe-button` directive. +To do so, use the following configuration: + +```python +thebe_config = { + "always_load": False +} +``` ## Configuration reference @@ -209,8 +220,9 @@ Here's a reference of all of the configuration values avialable to `sphinx-thebe Many of these eventually make their was into the `thebe` configuration. You can find a [reference for `thebe` configuration here](https://thebelab.readthedocs.io/en/latest/config_reference.html). -``` +```python thebe_config = { + "always_load": bool (default True) "repository_url": "", "repository_branch": "", "selector": "", diff --git a/sphinx_thebe/__init__.py b/sphinx_thebe/__init__.py index d1607da..3d1bcce 100644 --- a/sphinx_thebe/__init__.py +++ b/sphinx_thebe/__init__.py @@ -23,6 +23,7 @@ def st_static_path(app): def init_thebe_default_config(app, env, docnames): thebe_config = app.config.thebe_config defaults = { + "always_load": True, "selector": ".thebe", "selector_input": "pre", "selector_output": ".output", @@ -32,28 +33,41 @@ def init_thebe_default_config(app, env, docnames): thebe_config[key] = val -def _check_if_load_thebe(doctree, config_thebe): +def _bool(b): + if isinstance(b, bool): + return b + else: + return b in ["true", "True"] + + +def _do_load_thebe(doctree, config_thebe): """Decide whether to load thebe based on the page's context.""" - # Only load `thebe` if there is a thebe button somewhere - if not doctree or (not doctree.traverse(ThebeButtonNode)): - return + if not doctree: + return False + # If we aren't properly configured if not config_thebe: logger.warning("Didn't find `thebe_config` in conf.py, add to use thebe") - return + return False - return True + # Only load `thebe` if there is a thebe button somewhere + if doctree.traverse(ThebeButtonNode) or _bool(config_thebe.get("always_load")): + return True + else: + return False def init_thebe_core(app, pagename, templatename, context, doctree): """Load thebe assets if there's a thebe button on this page.""" config_thebe = app.config["thebe_config"] - if not _check_if_load_thebe(doctree, config_thebe): + if not _do_load_thebe(doctree, config_thebe): return # Add core libraries opts = {"async": "async"} - app.add_js_file(filename=f"https://unpkg.com/thebe@{THEBE_VERSION}/lib/index.js", **opts) + app.add_js_file( + filename=f"https://unpkg.com/thebe@{THEBE_VERSION}/lib/index.js", **opts + ) # Add configuration variables thebe_config = f""" @@ -68,7 +82,7 @@ def init_thebe_core(app, pagename, templatename, context, doctree): def update_thebe_context(app, doctree, docname): """Add thebe config nodes to this doctree.""" config_thebe = app.config["thebe_config"] - if not _check_if_load_thebe(doctree, config_thebe): + if not _do_load_thebe(doctree, config_thebe): return # Thebe configuration @@ -208,11 +222,13 @@ def setup(app): # Update the doctree with thebe-specific information if needed app.connect("doctree-resolved", update_thebe_context) - # Load the JS/CSS assets for thebe if needed + + # Load the JS/CSS assets for thebe if needed app.connect("html-page-context", init_thebe_core) # configuration for this tool app.add_config_value("thebe_config", {}, "html") + # override=True in case Jupyter Sphinx has already been loaded app.add_directive("thebe-button", ThebeButton, override=True) diff --git a/tests/test_build.py b/tests/test_build.py index cdb59e9..b638633 100644 --- a/tests/test_build.py +++ b/tests/test_build.py @@ -18,6 +18,7 @@ class SphinxBuild: path_html = path_build.joinpath("html") path_pg_index = path_html.joinpath("index.html") path_pg_config = path_html.joinpath("configure.html") + path_pg_chglg = path_html.joinpath("changelog.html") cmd_base = ["sphinx-build", ".", "_build/html", "-a", "-W"] def copy(self, path=None): @@ -68,3 +69,26 @@ def test_sphinx_thebe(file_regression, sphinx_build): launch_buttons = soup_conf.select(".thebe-launch-button") lb_text = "\n\n".join([ii.prettify() for ii in launch_buttons]) file_regression.check(lb_text, basename="launch_buttons", extension=".html") + + # Changelog has no thebe button directive, but should have the JS anyway + soup_chlg = BeautifulSoup( + Path(sphinx_build.path_pg_chglg).read_text(), "html.parser" + ) + assert "https://unpkg.com/thebe" in soup_chlg.prettify() + + +def test_always_load(file_regression, sphinx_build): + """Test building with thebe.""" + sphinx_build.copy() + + # Basic build with defaults + sphinx_build.build(cmd=["-D", "thebe_config.always_load=false"]) + + # Thebe should be loaded on a page *with* the directive and not on pages w/o it + soup_ix = BeautifulSoup(Path(sphinx_build.path_pg_index).read_text(), "html.parser") + assert "https://unpkg.com/thebe" in soup_ix.prettify() + # Changelog has no thebe button directive, so shouldn't have JS + soup_chlg = BeautifulSoup( + Path(sphinx_build.path_pg_chglg).read_text(), "html.parser" + ) + assert "https://unpkg.com/thebe" not in soup_chlg.prettify()