Skip to content

Commit 78d76d3

Browse files
committed
Support for MicroModal
https://micromodal.now.sh/
1 parent 1eea296 commit 78d76d3

File tree

6 files changed

+262
-28
lines changed

6 files changed

+262
-28
lines changed

MANIFEST.in

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,7 @@ include hoverxref/_static/js/tooltipster.bundle.min.js
55
include hoverxref/_static/css/tooltipster.bundle.min.css
66
include hoverxref/_static/css/tooltipster-sideTip-shadow.min.css
77
include hoverxref/_static/css/tooltipster.custom.css
8+
9+
include hoverxref/_static/js/micromodal.min.js
10+
include hoverxref/_static/css/micromodal.css
11+

docs/conf.py

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

74+
hoverxref_tooltip = False
75+
hoverxref_modal = True
76+
7477
versionwarning_messages = {
7578
'latest': 'This extension is currently in Beta state. '
7679
'This means that there may be some things not well supported or unexpected behavior. '

hoverxref/_static/css/micromodal.css

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/* https://gist.github.com/ghosh/4f94cf497d7090359a5c9f81caf60699 */
2+
.modal__overlay {
3+
position: fixed;
4+
top: 0;
5+
left: 0;
6+
right: 0;
7+
bottom: 0;
8+
background: rgba(0,0,0,0.6);
9+
display: flex;
10+
justify-content: center;
11+
align-items: center;
12+
z-index: 250;
13+
}
14+
15+
.modal__container {
16+
background-color: #fff;
17+
padding: 30px;
18+
max-width: 60%;
19+
max-height: 85%;
20+
border-radius: 4px;
21+
overflow-y: auto;
22+
box-sizing: border-box;
23+
z-index: 250;
24+
}
25+
26+
.modal__header {
27+
display: flex;
28+
justify-content: space-between;
29+
align-items: center;
30+
}
31+
32+
.modal__title {
33+
margin-top: 0;
34+
margin-bottom: 0;
35+
line-height: 1;
36+
font-size: 100%;
37+
color: #00449e;
38+
box-sizing: border-box;
39+
}
40+
41+
.modal__close {
42+
background: transparent;
43+
border: 0;
44+
}
45+
46+
.modal__header .modal__close:before { content: "\2715"; }
47+
48+
.modal__content {
49+
margin-top: 2rem;
50+
margin-bottom: 2rem;
51+
line-height: 1.5;
52+
color: rgba(0,0,0,.8);
53+
}
54+
55+
.modal__btn {
56+
font-size: .875rem;
57+
padding-left: 1rem;
58+
padding-right: 1rem;
59+
padding-top: .5rem;
60+
padding-bottom: .5rem;
61+
background-color: #e6e6e6;
62+
color: rgba(0,0,0,.8);
63+
border-radius: .25rem;
64+
border-style: none;
65+
border-width: 0;
66+
cursor: pointer;
67+
-webkit-appearance: button;
68+
text-transform: none;
69+
overflow: visible;
70+
line-height: 1.15;
71+
margin: 0;
72+
will-change: transform;
73+
-moz-osx-font-smoothing: grayscale;
74+
-webkit-backface-visibility: hidden;
75+
backface-visibility: hidden;
76+
-webkit-transform: translateZ(0);
77+
transform: translateZ(0);
78+
transition: -webkit-transform .25s ease-out;
79+
transition: transform .25s ease-out;
80+
transition: transform .25s ease-out,-webkit-transform .25s ease-out;
81+
}
82+
83+
.modal__btn:focus, .modal__btn:hover {
84+
-webkit-transform: scale(1.05);
85+
transform: scale(1.05);
86+
}
87+
88+
89+
@keyframes mmfadeIn {
90+
from { opacity: 0; }
91+
to { opacity: 1; }
92+
}
93+
94+
@keyframes mmfadeOut {
95+
from { opacity: 1; }
96+
to { opacity: 0; }
97+
}
98+
99+
@keyframes mmslideIn {
100+
from { transform: translateY(15%); }
101+
to { transform: translateY(0); }
102+
}
103+
104+
@keyframes mmslideOut {
105+
from { transform: translateY(0); }
106+
to { transform: translateY(-10%); }
107+
}
108+
109+
.micromodal-slide {
110+
display: none;
111+
}
112+
113+
.micromodal-slide.is-open {
114+
display: block;
115+
}
116+
117+
.micromodal-slide[aria-hidden="false"] .modal__overlay {
118+
animation: mmfadeIn .3s cubic-bezier(0.0, 0.0, 0.2, 1);
119+
}
120+
121+
.micromodal-slide[aria-hidden="false"] .modal__container {
122+
animation: mmslideIn .3s cubic-bezier(0, 0, .2, 1);
123+
}
124+
125+
.micromodal-slide[aria-hidden="true"] .modal__overlay {
126+
animation: mmfadeOut .3s cubic-bezier(0.0, 0.0, 0.2, 1);
127+
}
128+
129+
.micromodal-slide[aria-hidden="true"] .modal__container {
130+
animation: mmslideOut .3s cubic-bezier(0, 0, .2, 1);
131+
}
132+
133+
.micromodal-slide .modal__container,
134+
.micromodal-slide .modal__overlay {
135+
will-change: transform;
136+
}

hoverxref/_static/js/hoverxref.js_t

Lines changed: 100 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@ function reRender (instance, helper) {
1010
// https://stackoverflow.com/questions/5200545/how-to-recall-or-restart-mathjax
1111
if (mathjax) {
1212
if (typeof MathJax !== 'undefined') {
13-
console.debug('Triggering MathJax.Hub.Typeset()');
14-
MathJax.Hub.Queue((["Typeset", MathJax.Hub, helper.tooltip.id]));
13+
reLoadMathJax(helper.tooltip.id);
1514
} else {
1615
console.debug('Not triggering MathJax because it is not defined');
1716
};
@@ -24,7 +23,39 @@ function reRender (instance, helper) {
2423
}
2524

2625

26+
function reLoadMathJax(elementId) {
27+
console.debug('Triggering MathJax.Hub.Typeset()');
28+
MathJax.Hub.Queue((["Typeset", MathJax.Hub, elementId]));
29+
}
30+
31+
32+
function reLoadSphinxTabs() {
33+
if (sphinxtabs) {
34+
// https://github.com/djungelorm/sphinx-tabs
35+
console.debug('Triggering Sphinx Tabs rendering');
36+
(function(d, script) {
37+
// HACK: please, improve this code to call the content of "tab.js" without creating a script element
38+
39+
// Get the URL from the current generated page since it's not always the same
40+
var src = $('script[src$="sphinx_tabs/tabs.js"]')[0].src;
41+
42+
script = d.createElement('script');
43+
script.type = 'text/javascript';
44+
script.onload = function(){
45+
// remote script has loaded
46+
};
47+
script.src = src;
48+
d.getElementsByTagName('head')[0].appendChild(script);
49+
50+
// Once the script has been executed, we remove it from the DOM
51+
script.parentNode.removeChild(script);
52+
}(document));
53+
};
54+
};
55+
56+
2757
$(document).ready(function() {
58+
{% if hoverxref_tooltip or not hoverxref_modal %}
2859
$('.hoverxref').tooltipster({
2960
theme: {{ hoverxref_tooltip_theme }},
3061
interactive: {{ 'true' if hoverxref_tooltip_interactive else 'false' }},
@@ -48,7 +79,6 @@ $(document).ready(function() {
4879
// TODO: improve URL handling here
4980
var url = '{{ hoverxref_tooltip_api_host }}' + '/api/v2/embed/?' + 'project=' + project + '&version=' + version + '&doc=' + doc + '&section=' + section;
5081
$.get(url, function(data) {
51-
5282
// call the 'content' method to update the content of our tooltip with the returned data.
5383
// note: this content update will trigger an update animation (see the updateAnimation option)
5484
instance.content(data['content']);
@@ -63,34 +93,77 @@ $(document).ready(function() {
6393
// most of Read the Docs Sphinx theme bases its style on "rst-content".
6494
// We add that class to the tooltipser HTML tag here by default or a user-defined one.
6595
helper.tooltip.classList.add('{{ hoverxref_tooltip_class }}');
66-
67-
if (sphinxtabs) {
68-
// https://github.com/djungelorm/sphinx-tabs
69-
console.debug('Triggering Sphinx Tabs rendering');
70-
(function(d, script) {
71-
// HACK: please, improve this code to call the content of "tab.js" without creating a script element
72-
73-
// Get the URL from the current generated page since it's not always the same
74-
var src = $('script[src$="sphinx_tabs/tabs.js"]')[0].src;
75-
76-
script = d.createElement('script');
77-
script.type = 'text/javascript';
78-
script.onload = function(){
79-
// remote script has loaded
80-
};
81-
script.src = src;
82-
d.getElementsByTagName('head')[0].appendChild(script);
83-
84-
// Once the script has been executed, we remove it from the DOM
85-
script.parentNode.removeChild(script);
86-
}(document));
87-
};
88-
96+
reLoadSphinxTabs();
8997
setTimeout(
9098
reRender,
9199
50,
92100
instance,
93101
helper
94102
);
95103
}
96-
})});
104+
})
105+
{% endif %}
106+
107+
{% if hoverxref_modal and not hoverxref_tooltip %}
108+
var modalHtml = `
109+
<div class="modal micromodal-slide {{ hoverxref_modal_class }}" id="micromodal" aria-hidden="true">
110+
<div class="modal__overlay" tabindex="-1" data-micromodal-close>
111+
<div class="modal__container" role="dialog" aria-modal="true" aria-labelledby="micromodal-title">
112+
<header class="modal__header">
113+
<h2 class="modal__title" id="micromodal-title"></h2>
114+
<button class="modal__close" aria-label="Close modal" data-micromodal-close></button>
115+
</header>
116+
<main class="modal__content" id="micromodal-content"></main>
117+
<footer class="modal__footer">
118+
<button class="modal__btn" data-micromodal-close aria-label="Close this dialog window">Close</button>
119+
</footer>
120+
</div>
121+
</div>
122+
</div>
123+
`
124+
$('body').append(modalHtml);
125+
126+
var delay = {{ hoverxref_modal_hover_delay }}, setTimeoutConst;
127+
$('.hoverxref').hover(function(event) {
128+
event.preventDefault();
129+
130+
setTimeoutConst = setTimeout(function(){
131+
showModal(event.target.parentNode);
132+
}, delay);
133+
}, function(){
134+
clearTimeout(setTimeoutConst);
135+
});
136+
137+
function showModal(element) {
138+
var $origin = $(element);
139+
var project = $origin.data('project');
140+
var version = $origin.data('version');
141+
var doc = $origin.data('doc');
142+
var section = $origin.data('section');
143+
console.debug('Data: project=' + project + ' version=' + version + ' doc=' + doc + ' section=' + section);
144+
var url = '{{ hoverxref_tooltip_api_host }}' + '/api/v2/embed/?' + 'project=' + project + '&version=' + version + '&doc=' + doc + '&section=' + section;
145+
146+
$.get(url, function(data) {
147+
var content = $('<div></div>');
148+
content.html(data['content'][0]);
149+
150+
var title = $('h1', content)[0] || '';
151+
content.replaceWith('h1', '');
152+
153+
$('#micromodal-title').html(title);
154+
$('#micromodal-content').html(content);
155+
MicroModal.show('micromodal', {
156+
disableScroll: false,
157+
});
158+
reLoadSphinxTabs();
159+
if (mathjax) {
160+
if (typeof MathJax !== 'undefined') {
161+
reLoadMathJax('micromodal');
162+
} else {
163+
console.debug('Not triggering MathJax because it is not defined');
164+
};
165+
};
166+
});
167+
};
168+
{% endif %}
169+
});

hoverxref/_static/js/micromodal.min.js

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

hoverxref/extension.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@
88
from .domains import HoverXRefPythonDomain, HoverXRefStandardDomain
99
from .translators import HoverXRefHTMLTranslator
1010

11-
ASSETS_FILES = [
11+
HOVERXREF_ASSETS_FILES = [
1212
'js/hoverxref.js_t', # ``_t`` tells Sphinx this is a template
13+
]
14+
15+
TOOLTIP_ASSETS_FILES = [
16+
# Tooltipster's Styles
1317
'js/tooltipster.bundle.min.js',
1418
'css/tooltipster.custom.css',
1519
'css/tooltipster.bundle.min.css',
@@ -22,6 +26,12 @@
2226
'css/tooltipster-sideTip-borderless.min.css',
2327
]
2428

29+
MODAL_ASSETS_FILES = [
30+
'js/micromodal.min.js',
31+
'css/micromodal.css',
32+
]
33+
34+
ASSETS_FILES = HOVERXREF_ASSETS_FILES + TOOLTIP_ASSETS_FILES + MODAL_ASSETS_FILES
2535

2636
def copy_asset_files(app, exception):
2737
"""
@@ -99,6 +109,7 @@ def setup(app):
99109
app.add_config_value('hoverxref_roles', [], 'env')
100110
app.add_config_value('hoverxref_domains', [], 'env')
101111

112+
app.add_config_value('hoverxref_tooltip', False, 'env')
102113
app.add_config_value('hoverxref_tooltip_api_host', 'https://readthedocs.org', 'env')
103114
app.add_config_value('hoverxref_tooltip_theme', ['tooltipster-shadow', 'tooltipster-shadow-custom'], 'env')
104115
app.add_config_value('hoverxref_tooltip_interactive', True, 'env')
@@ -109,6 +120,12 @@ def setup(app):
109120
app.add_config_value('hoverxref_tooltip_content', 'Loading...', 'env')
110121
app.add_config_value('hoverxref_tooltip_class', 'rst-content', 'env')
111122

123+
124+
app.add_config_value('hoverxref_modal', False, 'env')
125+
app.add_config_value('hoverxref_modal_hover_delay', 350, 'env')
126+
app.add_config_value('hoverxref_modal_class', 'rst-content', 'env')
127+
128+
112129
app.set_translator('html', HoverXRefHTMLTranslator, override=True)
113130

114131
# Read the Docs use ``readthedocs`` as the name of the build, so we need to

0 commit comments

Comments
 (0)