Skip to content

Commit 7bf9552

Browse files
committed
Add support for both styles in the same documentation
1 parent 8153676 commit 7bf9552

File tree

8 files changed

+106
-65
lines changed

8 files changed

+106
-65
lines changed

docs/_images/modal-example.png

-44.4 KB
Binary file not shown.

docs/_images/tooltip-example.png

-45.7 KB
Binary file not shown.

docs/conf.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,6 @@
7171
hoverxref_sphinxtabs = True
7272
hoverxref_mathjax = True
7373

74-
hoverxref_type = 'modal'
75-
7674
versionwarning_messages = {
7775
'latest': 'This extension is currently in Beta state. '
7876
'This means that there may be some things not well supported or unexpected behavior. '

docs/index.rst

Lines changed: 37 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,63 @@
11
Welcome to sphinx-hoverxref!
22
============================
33

4-
``sphinx-hoverxref`` is a Sphinx_ extension to show a floating window (tooltips or modal dialogues) on the cross references of the documentation embedding the content of the linked section on them. With ``sphinx-hoverxref``, you don't need to click a link to see what's in there.
4+
``sphinx-hoverxref`` is a Sphinx_ extension to show a floating window (*tooltips* or *modal* dialogues) on the cross references of the documentation embedding the content of the linked section on them. With ``sphinx-hoverxref``, you don't need to click a link to see what's in there.
55

6-
We currently support two different types of floating windows: Tooltip_ and Modal_.
76

7+
Usage
8+
-----
89

9-
Tooltip
10-
-------
10+
To show a floating window, use the role ``hoverxref`` to link to any document or section and embed its content into it.
11+
We currently support two different types of floating windows: Tooltip and Modal.
1112

12-
By defining :confval:`hoverxref_type <hoverxref_type>` as ``'tooltip'`` (default) you will get a tooltip when hover references.
1313

14-
.. figure:: _images/tooltip-example.png
15-
:width: 75%
16-
:class: example
14+
.. tabs::
1715

16+
.. tab:: Default
1817

19-
Modal
20-
-----
18+
Writing this reStructuredText in your document:
2119

22-
By defining :confval:`hoverxref_type <hoverxref_type>` as ``'modal'`` you will get a modal when hover references.
20+
.. code-block:: rst
2321
24-
.. image:: _images/modal-example.png
25-
:width: 75%
26-
:class: example
22+
This will :hoverxref:`show a floating window <hoverxref:hoverxref>` in the linked words.
2723
24+
it will be rendered to:
25+
26+
This will :hoverxref:`show a floating window <hoverxref:hoverxref>` in the linked words.
27+
28+
.. note::
29+
30+
The default style (tooltip or modal) is defined by the config :confval:`hoverxref_type <hoverxref_type>`.
31+
32+
33+
.. tab:: Tooltip style
34+
35+
To *force* the floating window to be a tooltip, you can use ``:hoverxreftooltip:`` role instead.
36+
37+
.. code-block:: rst
38+
39+
This will :hoverxreftooltip:`show a tooltip <hoverxref:hoverxref>` in the linked words.
40+
41+
it will be rendered to:
42+
43+
This will :hoverxreftooltip:`show a tooltip <hoverxref:hoverxref>` in the linked words.
2844

29-
Usage
30-
-----
3145

32-
To show a floating window on a reference, use the role ``hoverxref`` to link to any document or section.
46+
.. tab:: Modal style
3347

34-
Writing this reStructuredText in your document:
48+
To *force* the floating window to be a modal, you can use ``:hoverxrefmodal:`` role instead.
3549

36-
.. code-block:: rst
50+
.. code-block:: rst
3751
38-
This will :hoverxref:`show a floating window <hoverxref:hoverxref>` in the linked words.
52+
This will :hoverxrefmodal:`show a modal <hoverxref:hoverxref>` in the linked words.
3953
40-
it will be rendered to:
54+
it will be rendered to:
4155

42-
This will :hoverxref:`show a floating window <hoverxref:hoverxref>` in the linked words.
56+
This will :hoverxrefmodal:`show a modal <hoverxref:hoverxref>` in the linked words.
4357

4458
.. tip::
4559

46-
This new ``hoverxref`` role is an alias of the ``ref`` role and works in the same.
60+
These new roles are alias of the ``ref`` role and works in the same.
4761
See :ref:`usage:usage` for more detailed information about this and other examples.
4862

4963

hoverxref/_static/js/hoverxref.js_t

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ function reLoadSphinxTabs() {
5757

5858

5959
$(document).ready(function() {
60-
{% if hoverxref_type == 'tooltip' %}
61-
$('.hoverxref').tooltipster({
60+
$('.hoverxref.tooltip').tooltipster({
6261
theme: {{ hoverxref_tooltip_theme }},
6362
interactive: {{ 'true' if hoverxref_tooltip_interactive else 'false' }},
6463
maxWidth: {{ hoverxref_tooltip_maxwidth }},
@@ -105,9 +104,7 @@ $(document).ready(function() {
105104
);
106105
}
107106
})
108-
{% endif %}
109107

110-
{% if hoverxref_type == 'modal' %}
111108
var modalHtml = `
112109
<div class="modal micromodal-slide {{ hoverxref_modal_class }}" id="micromodal" aria-hidden="true">
113110
<div class="modal__overlay" tabindex="-1" data-micromodal-close>
@@ -149,9 +146,10 @@ $(document).ready(function() {
149146
var project = element.data('project');
150147
var version = element.data('version');
151148
var doc = element.data('doc');
149+
var docpath = element.data('docpath');
152150
var section = element.data('section');
153-
console.debug('Data: project=' + project + ' version=' + version + ' doc=' + doc + ' section=' + section);
154-
var url = '{{ hoverxref_api_host }}' + '/api/v2/embed/?' + 'project=' + project + '&version=' + version + '&doc=' + doc + '&section=' + section;
151+
console.debug('Data: project=' + project + ' version=' + version + ' doc=' + doc + ' path=' + docpath + ' section=' + section);
152+
var url = '{{ hoverxref_api_host }}' + '/api/v2/embed/?' + 'project=' + project + '&version=' + version + '&doc=' + doc + '&path=' + docpath + '&section=' + section;
155153

156154
$.get(url, function(data) {
157155
var content = $('<div></div>');
@@ -194,7 +192,7 @@ $(document).ready(function() {
194192
};
195193

196194
var delay = {{ hoverxref_modal_hover_delay }}, setTimeoutConst;
197-
$('.hoverxref').hover(function(event) {
195+
$('.hoverxref.modal').hover(function(event) {
198196
var element = $(this);
199197
console.debug('Event: ' + event + ' Element: ' + element);
200198
event.preventDefault();
@@ -205,5 +203,4 @@ $(document).ready(function() {
205203
}, function(){
206204
clearTimeout(setTimeoutConst);
207205
});
208-
{% endif %}
209206
});

hoverxref/domains.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@
66

77
class HoverXRefBaseDomain:
88

9+
hoverxref_types = (
10+
'hoverxref',
11+
'hoverxreftooltip',
12+
'hoverxrefmodal',
13+
)
14+
915
def _is_hoverxref_configured(self, env):
1016
project = env.config.hoverxref_project
1117
version = env.config.hoverxref_version
1218
return project and version
1319

14-
def _inject_hoverxref_data(self, env, refnode, docname, docpath, labelid):
15-
refnode.replace_attr('classes', ['hoverxref'])
20+
def _inject_hoverxref_data(self, env, refnode, typ, docname, docpath, labelid):
21+
type_class = 'tooltip' if typ == 'hoverxreftooltip' else ('modal' if typ == 'hoverxrefmodal' else env.config.hoverxref_default_type)
22+
refnode.replace_attr('classes', ['hoverxref', type_class])
1623

1724
project = env.config.hoverxref_project
1825
version = env.config.hoverxref_version
@@ -32,23 +39,23 @@ def _get_docpath(self, builder, docname):
3239

3340
class HoverXRefPythonDomainMixin(HoverXRefBaseDomain):
3441

35-
def resolve_xref(self, env, fromdocname, builder, type, target, node, contnode):
36-
refnode = super().resolve_xref(env, fromdocname, builder, type, target, node, contnode)
42+
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
43+
refnode = super().resolve_xref(env, fromdocname, builder, typ, target, node, contnode)
3744
if refnode is None:
3845
return
3946

4047
modname = node.get('py:module')
4148
clsname = node.get('py:class')
4249
searchmode = node.hasattr('refspecific') and 1 or 0
4350
matches = self.find_obj(env, modname, clsname, target,
44-
type, searchmode)
51+
typ, searchmode)
4552
name, obj = matches[0]
4653

4754
if self._is_hoverxref_configured(env):
4855
docname, labelid = obj[0], name
4956
docpath = self._get_docpath(builder, docname)
5057

51-
self._inject_hoverxref_data(env, refnode, docname, docpath, labelid)
58+
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
5259
logger.info(
5360
':ref: _hoverxref injected: fromdocname=%s %s',
5461
fromdocname,
@@ -70,7 +77,7 @@ class HoverXRefStandardDomainMixin(HoverXRefBaseDomain):
7077
"""
7178

7279
def resolve_xref(self, env, fromdocname, builder, typ, target, node, contnode):
73-
if typ == 'hoverxref':
80+
if typ in self.hoverxref_types:
7481
resolver = self._resolve_ref_xref
7582
return resolver(env, fromdocname, builder, typ, target, node, contnode)
7683

@@ -82,16 +89,16 @@ def _resolve_ref_xref(self, env, fromdocname, builder, typ, target, node, contno
8289
if refnode is None:
8390
return
8491

85-
if not self._is_hoverxref_configured(env) and typ == 'hoverxref':
92+
if not self._is_hoverxref_configured(env) and typ in self.hoverxref_types:
8693
# Using ``:hoverxref:`` role without having hoverxref configured
8794
# properly. Log a warning.
8895
logger.warning('hoverxref role is not fully configured.')
8996

90-
if self._is_hoverxref_configured(env) and (env.config.hoverxref_auto_ref or typ == 'hoverxref'):
97+
if self._is_hoverxref_configured(env) and (env.config.hoverxref_auto_ref or typ in self.hoverxref_types):
9198
docname, labelid, _ = get_ref_xref_data(self, node, target)
9299
docpath = self._get_docpath(builder, docname)
93100

94-
self._inject_hoverxref_data(env, refnode, docname, docpath, labelid)
101+
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
95102
logger.info(
96103
':ref: _hoverxref injected: fromdocname=%s %s',
97104
fromdocname,
@@ -109,7 +116,7 @@ def _resolve_obj_xref(self, env, fromdocname, builder, typ, target, node, contno
109116
if self._is_hoverxref_configured(env):
110117
docpath = self._get_docpath(builder, docname)
111118

112-
self._inject_hoverxref_data(env, refnode, docname, docpath, labelid)
119+
self._inject_hoverxref_data(env, refnode, typ, docname, docpath, labelid)
113120
logger.info(
114121
':%s: _hoverxref injected: fromdocname=%s %s',
115122
typ,

hoverxref/extension.py

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
from sphinx.util import logging
99

1010
from . import version
11-
from .domains import HoverXRefPythonDomainMixin, HoverXRefStandardDomainMixin
11+
from .domains import (
12+
HoverXRefBaseDomain,
13+
HoverXRefPythonDomainMixin,
14+
HoverXRefStandardDomainMixin,
15+
)
1216
from .translators import HoverXRefHTMLTranslatorMixin
1317

1418
logger = logging.getLogger(__name__)
@@ -82,15 +86,16 @@ def setup_domains(app, config):
8286
``_hoverxref`` attributes.
8387
"""
8488
# Add ``hoverxref`` role replicating the behavior of ``ref``
85-
app.add_role_to_domain(
86-
'std',
87-
'hoverxref',
88-
XRefRole(
89-
lowercase=True,
90-
innernodeclass=nodes.inline,
91-
warn_dangling=True,
92-
),
93-
)
89+
for role in HoverXRefBaseDomain.hoverxref_types:
90+
app.add_role_to_domain(
91+
'std',
92+
role,
93+
XRefRole(
94+
lowercase=True,
95+
innernodeclass=nodes.inline,
96+
warn_dangling=True,
97+
),
98+
)
9499

95100
domain = types.new_class(
96101
'HoverXRefStandardDomain',
@@ -176,9 +181,6 @@ def setup_theme(app, exception):
176181
Add a small custom CSS file for a specific theme and set hoverxref configs
177182
(if not overwritten by the user) with better defaults for these themes.
178183
"""
179-
if app.config.hoverxref_type != 'modal':
180-
return
181-
182184
css_file = None
183185
theme = app.config.html_theme
184186
default, rebuild, types = app.config.values.get('hoverxref_modal_class')
@@ -228,7 +230,7 @@ def setup(app):
228230
app.add_config_value('hoverxref_sphinxtabs', False, 'env')
229231
app.add_config_value('hoverxref_roles', [], 'env')
230232
app.add_config_value('hoverxref_domains', [], 'env')
231-
app.add_config_value('hoverxref_type', 'tooltip', 'env')
233+
app.add_config_value('hoverxref_default_type', 'tooltip', 'env')
232234
app.add_config_value('hoverxref_api_host', 'https://readthedocs.org', 'env')
233235

234236
# Tooltipster settings

tests/test_htmltag.py

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def test_project_version_settings(app, status, warning):
7474

7575
chunks = [
7676
'<a class="reference internal" href="chapter-i.html#chapter-i"><span class="std std-ref">This a :ref: to Chapter I</span></a>',
77-
'<a class="hoverxref reference internal" data-doc="chapter-i" data-docpath="/chapter-i.html" data-project="myproject" data-section="section-i" data-version="myversion" href="chapter-i.html#section-i"><span class="std std-ref">This a :hoverxref: to Chapter I, Section I</span></a>',
77+
'<a class="hoverxref tooltip reference internal" data-doc="chapter-i" data-docpath="/chapter-i.html" data-project="myproject" data-section="section-i" data-version="myversion" href="chapter-i.html#section-i"><span class="std std-ref">This a :hoverxref: to Chapter I, Section I</span></a>',
7878
]
7979

8080
for chunk in chunks:
@@ -123,7 +123,7 @@ def test_autosectionlabel_project_version_settings(app, status, warning):
123123

124124
chunks = [
125125
'<a class="reference internal" href="chapter-i.html#chapter-i"><span class="std std-ref">This a :ref: to Chapter I</span></a>.',
126-
'<a class="hoverxref reference internal" data-doc="chapter-i" data-docpath="/chapter-i.html" data-project="myproject" data-section="chapter-i" data-version="myversion" href="chapter-i.html#chapter-i"><span class="std std-ref">This a :hoverxref: to Chapter I</span></a>',
126+
'<a class="hoverxref tooltip reference internal" data-doc="chapter-i" data-docpath="/chapter-i.html" data-project="myproject" data-section="chapter-i" data-version="myversion" href="chapter-i.html#chapter-i"><span class="std std-ref">This a :hoverxref: to Chapter I</span></a>',
127127
]
128128

129129
for chunk in chunks:
@@ -141,8 +141,8 @@ def test_custom_object(app, status, warning):
141141
content = open(path).read()
142142

143143
chunks = [
144-
'<a class="hoverxref reference internal" data-doc="configuration" data-docpath="/configuration.html" data-project="myproject" data-section="confval-conf-title" data-version="myversion" href="configuration.html#confval-conf-title"><code class="xref std std-confval docutils literal notranslate"><span class="pre">This</span> <span class="pre">is</span> <span class="pre">a</span> <span class="pre">:confval:</span> <span class="pre">to</span> <span class="pre">conf-title</span></code></a>',
145-
'<a class="hoverxref reference internal" data-doc="configuration" data-docpath="/configuration.html" data-project="myproject" data-section="configuration" data-version="myversion" href="configuration.html#configuration"><span class="std std-ref">This is a :hoverxref: to Configuration document</span></a>',
144+
'<a class="hoverxref tooltip reference internal" data-doc="configuration" data-docpath="/configuration.html" data-project="myproject" data-section="confval-conf-title" data-version="myversion" href="configuration.html#confval-conf-title"><code class="xref std std-confval docutils literal notranslate"><span class="pre">This</span> <span class="pre">is</span> <span class="pre">a</span> <span class="pre">:confval:</span> <span class="pre">to</span> <span class="pre">conf-title</span></code></a>',
145+
'<a class="hoverxref tooltip reference internal" data-doc="configuration" data-docpath="/configuration.html" data-project="myproject" data-section="configuration" data-version="myversion" href="configuration.html#configuration"><span class="std std-ref">This is a :hoverxref: to Configuration document</span></a>',
146146
]
147147

148148
for chunk in chunks:
@@ -162,9 +162,32 @@ def test_python_domain(app, status, warning):
162162
content = open(path).read()
163163

164164
chunks = [
165-
'<a class="hoverxref reference internal" data-doc="api" data-docpath="/api.html" data-project="myproject" data-section="hoverxref.extension.HoverXRefStandardDomainMixin" data-version="myversion" href="api.html#hoverxref.extension.HoverXRefStandardDomainMixin" title="hoverxref.extension.HoverXRefStandardDomainMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">This</span> <span class="pre">is</span> <span class="pre">a</span> <span class="pre">:py:class:</span> <span class="pre">role</span> <span class="pre">to</span> <span class="pre">a</span> <span class="pre">Python</span> <span class="pre">object</span></code></a>',
166-
'<a class="hoverxref reference internal" data-doc="api" data-docpath="/api.html" data-project="myproject" data-section="hoverxref.extension" data-version="myversion" href="api.html#module-hoverxref.extension" title="hoverxref.extension"><code class="xref py py-mod docutils literal notranslate"><span class="pre">hoverxref.extension</span></code></a>',
167-
'<a class="hoverxref reference internal" data-doc="api" data-docpath="/api.html" data-project="myproject" data-section="hoverxref.utils.get_ref_xref_data" data-version="myversion" href="api.html#hoverxref.utils.get_ref_xref_data" title="hoverxref.utils.get_ref_xref_data"><code class="xref py py-func docutils literal notranslate"><span class="pre">hoverxref.utils.get_ref_xref_data()</span></code></a>',
165+
'<a class="hoverxref tooltip reference internal" data-doc="api" data-docpath="/api.html" data-project="myproject" data-section="hoverxref.extension.HoverXRefStandardDomainMixin" data-version="myversion" href="api.html#hoverxref.extension.HoverXRefStandardDomainMixin" title="hoverxref.extension.HoverXRefStandardDomainMixin"><code class="xref py py-class docutils literal notranslate"><span class="pre">This</span> <span class="pre">is</span> <span class="pre">a</span> <span class="pre">:py:class:</span> <span class="pre">role</span> <span class="pre">to</span> <span class="pre">a</span> <span class="pre">Python</span> <span class="pre">object</span></code></a>',
166+
'<a class="hoverxref tooltip reference internal" data-doc="api" data-docpath="/api.html" data-project="myproject" data-section="hoverxref.extension" data-version="myversion" href="api.html#module-hoverxref.extension" title="hoverxref.extension"><code class="xref py py-mod docutils literal notranslate"><span class="pre">hoverxref.extension</span></code></a>',
167+
'<a class="hoverxref tooltip reference internal" data-doc="api" data-docpath="/api.html" data-project="myproject" data-section="hoverxref.utils.get_ref_xref_data" data-version="myversion" href="api.html#hoverxref.utils.get_ref_xref_data" title="hoverxref.utils.get_ref_xref_data"><code class="xref py py-func docutils literal notranslate"><span class="pre">hoverxref.utils.get_ref_xref_data()</span></code></a>',
168+
]
169+
170+
for chunk in chunks:
171+
assert chunk in content
172+
173+
174+
@pytest.mark.sphinx(
175+
srcdir=srcdir,
176+
confoverrides={
177+
'hoverxref_project': 'myproject',
178+
'hoverxref_version': 'myversion',
179+
'hoverxref_default_type': 'modal',
180+
},
181+
)
182+
def test_project_version_settings(app, status, warning):
183+
app.build()
184+
path = app.outdir / 'index.html'
185+
assert path.exists() is True
186+
content = open(path).read()
187+
188+
chunks = [
189+
'<a class="reference internal" href="chapter-i.html#chapter-i"><span class="std std-ref">This a :ref: to Chapter I</span></a>',
190+
'<a class="hoverxref modal reference internal" data-doc="chapter-i" data-docpath="/chapter-i.html" data-project="myproject" data-section="section-i" data-version="myversion" href="chapter-i.html#section-i"><span class="std std-ref">This a :hoverxref: to Chapter I, Section I</span></a>',
168191
]
169192

170193
for chunk in chunks:

0 commit comments

Comments
 (0)