Skip to content

Commit d69ce1f

Browse files
brichetmartinRenou
andauthored
Transfer search parameters from page URL to jupyterlite (#108)
* Add directive to transfert URL search parameters from the documentation page to jupyterlite * Add documentation on the directive * prettier * Add an option to transfer all the parameters * Allow True, False or ["param1", "param2"] as options * Adds regex to checks parameters * Update jupyterlite_sphinx/jupyterlite_sphinx.py Co-authored-by: martinRenou <[email protected]> --------- Co-authored-by: martinRenou <[email protected]>
1 parent 83663db commit d69ce1f

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

docs/directives/jupyterlite.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,8 @@ You can also pass a Notebook file to open automatically:
3535
:prompt: Try JupyterLite!
3636
:prompt_color: #00aa42
3737
```
38+
39+
The directive `search_params` allows to transfer some search parameters from the documentation URL to the Jupyterlite URL.\
40+
Jupyterlite will then be able to fetch these parameters from its own URL.\
41+
For example `:search_params: ["param1", "param2"]` will transfer the parameters *param1* and *param2*.
42+
Use a boolean value to transfer all or none of the parameters (default to none): `:search_params: True`

jupyterlite_sphinx/jupyterlite_sphinx.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,27 @@ window.jupyterliteShowIframe = (tryItButtonId, iframeSrc) => {
1111
tryItButton.classList.remove('jupyterlite_sphinx_try_it_button_unclicked');
1212
tryItButton.classList.add('jupyterlite_sphinx_try_it_button_clicked');
1313
}
14+
15+
window.jupyterliteConcatSearchParams = (iframeSrc, params) => {
16+
const baseURL = window.location.origin;
17+
const iframeUrl = new URL(iframeSrc, baseURL);
18+
19+
let pageParams = new URLSearchParams(window.location.search);
20+
21+
if (params === true) {
22+
params = Array.from(pageParams.keys());
23+
} else if (params === false) {
24+
params = [];
25+
} else if (!Array.isArray(params)) {
26+
console.error('The search parameters are not an array');
27+
}
28+
29+
params.forEach(param => {
30+
value = pageParams.get(param);
31+
if (value !== null) {
32+
iframeUrl.searchParams.append(param, value);
33+
}
34+
});
35+
36+
return iframeUrl.toString().replace(baseURL, '');
37+
}

jupyterlite_sphinx/jupyterlite_sphinx.py

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import tempfile
55
from warnings import warn
66
import glob
7+
import re
78

89
from pathlib import Path
910

@@ -51,6 +52,7 @@ def __init__(
5152
height="100%",
5253
prompt=False,
5354
prompt_color=None,
55+
search_params=[],
5456
**attributes,
5557
):
5658
super().__init__(
@@ -60,10 +62,12 @@ def __init__(
6062
height=height,
6163
prompt=prompt,
6264
prompt_color=prompt_color,
65+
search_params=search_params,
6366
)
6467

6568
def html(self):
6669
iframe_src = self["iframe_src"]
70+
search_params = self["search_params"]
6771

6872
if self["prompt"]:
6973
prompt = (
@@ -76,13 +80,24 @@ def html(self):
7680
placeholder_id = uuid4()
7781
container_style = f'width: {self["width"]}; height: {self["height"]};'
7882

79-
return (
80-
f"<div class=\"jupyterlite_sphinx_iframe_container\" style=\"{container_style}\" onclick=window.jupyterliteShowIframe('{placeholder_id}','{iframe_src}')>"
81-
f' <div id={placeholder_id} class="jupyterlite_sphinx_try_it_button jupyterlite_sphinx_try_it_button_unclicked" style="background-color: {prompt_color};">'
82-
f" {prompt}"
83-
" </div>"
84-
"</div>"
85-
)
83+
return f"""
84+
<div
85+
class=\"jupyterlite_sphinx_iframe_container\"
86+
style=\"{container_style}\"
87+
onclick=\"window.jupyterliteShowIframe(
88+
'{placeholder_id}',
89+
window.jupyterliteConcatSearchParams('{iframe_src}', {search_params})
90+
)\"
91+
>
92+
<div
93+
id={placeholder_id}
94+
class=\"jupyterlite_sphinx_try_it_button jupyterlite_sphinx_try_it_button_unclicked\"
95+
style=\"background-color: {prompt_color};\"
96+
>
97+
{prompt}
98+
</div>
99+
</div>
100+
"""
86101

87102
return (
88103
f'<iframe src="{iframe_src}"'
@@ -196,6 +211,7 @@ class RepliteDirective(SphinxDirective):
196211
"theme": directives.unchanged,
197212
"prompt": directives.unchanged,
198213
"prompt_color": directives.unchanged,
214+
"search_params": directives.unchanged,
199215
}
200216

201217
def run(self):
@@ -205,6 +221,8 @@ def run(self):
205221
prompt = self.options.pop("prompt", False)
206222
prompt_color = self.options.pop("prompt_color", None)
207223

224+
search_params = search_params_parser(self.options.pop("search_params", ""))
225+
208226
prefix = os.path.relpath(
209227
os.path.join(self.env.app.srcdir, JUPYTERLITE_DIR),
210228
os.path.dirname(self.get_source_info()[0]),
@@ -218,6 +236,7 @@ def run(self):
218236
prompt=prompt,
219237
prompt_color=prompt_color,
220238
content=self.content,
239+
search_params=search_params,
221240
lite_options=self.options,
222241
)
223242
]
@@ -233,6 +252,7 @@ class _LiteDirective(SphinxDirective):
233252
"theme": directives.unchanged,
234253
"prompt": directives.unchanged,
235254
"prompt_color": directives.unchanged,
255+
"search_params": directives.unchanged,
236256
}
237257

238258
def run(self):
@@ -242,6 +262,8 @@ def run(self):
242262
prompt = self.options.pop("prompt", False)
243263
prompt_color = self.options.pop("prompt_color", None)
244264

265+
search_params = search_params_parser(self.options.pop("search_params", ""))
266+
245267
source_location = os.path.dirname(self.get_source_info()[0])
246268

247269
prefix = os.path.relpath(
@@ -276,6 +298,7 @@ def run(self):
276298
height=height,
277299
prompt=prompt,
278300
prompt_color=prompt_color,
301+
search_params=search_params,
279302
lite_options=self.options,
280303
)
281304
]
@@ -476,3 +499,18 @@ def setup(app):
476499
app.add_css_file("jupyterlite_sphinx.css")
477500

478501
app.add_js_file("jupyterlite_sphinx.js")
502+
503+
504+
def search_params_parser(search_params: str) -> str:
505+
pattern = re.compile(r"^\[(?:\s*[\"']{1}([^=\s\,&=\?\/]+)[\"']{1}\s*\,?)+\]$")
506+
if not search_params:
507+
return ""
508+
if search_params in ["True", "False"]:
509+
return search_params.lower()
510+
elif pattern.match(search_params):
511+
return search_params.replace('"', "'")
512+
else:
513+
raise ValueError(
514+
'The search_params directive must be either True, False or ["param1", "param2"].\n'
515+
'The params name shouldn\'t contain any of the following characters ["\\", "\'", """, ",", "?", "=", "&", " ").'
516+
)

0 commit comments

Comments
 (0)