Skip to content

Commit 472dbca

Browse files
committed
fix CORS issues in notebook
1 parent 70c3642 commit 472dbca

File tree

6 files changed

+88
-27
lines changed

6 files changed

+88
-27
lines changed

examples/chart.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import React from '../react.js';
2-
import { VictoryBar, VictoryChart, VictoryAxis } from '../victory.js';
3-
import htm from "../htm.js";
1+
import React from '../web_modules/react.js';
2+
import { VictoryBar, VictoryChart, VictoryAxis } from '../web_modules/victory.js';
3+
import htm from "../web_modules/htm.js";
44

55
const html = htm.bind(React.createElement);
66

requirements/extras.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# extra=sanic
2-
sanic >=19.12.0, <20.0
2+
sanic <19.12.0
33
sanic-cors >=0.9.9, <1.0
44

55
# extra=matplotlib

src/idom/client/__init__.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ def import_path(name: str) -> Optional[str]:
2323

2424

2525
def define_module(name: str, source: str) -> str:
26-
path = CLIENT_DIR / "web_modules"
27-
for n in name.split("/"):
26+
path = CLIENT_DIR
27+
for n in ["etc_modules"] + name.split("/"):
2828
if not path.exists():
2929
path.mkdir()
3030
path /= n
3131
module = path.with_suffix(".js")
3232
with module.open("w+") as f:
3333
f.write(source)
34-
return _web_module(name)
34+
return _etc_module(name)
3535

3636

3737
def install(*dependencies: str) -> None:
@@ -98,3 +98,7 @@ def _run_subprocess(args: List[str], cwd: Union[str, Path]):
9898

9999
def _web_module(name: str) -> str:
100100
return f"../web_modules/{name}.js"
101+
102+
103+
def _etc_module(name: str) -> str:
104+
return f"../etc_modules/{name}.js"

src/idom/client/core_modules/layout.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ function Layout({ endpoint }) {
6464
}
6565

6666
function Element({ modelState, model, sendEvent }) {
67-
console.log(model)
6867
const children = elementChildren(modelState, model, sendEvent);
6968
const attributes = elementAttributes(model, sendEvent);
7069
if (model.importSource) {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from '../web_modules/react.js';
2+
import { VictoryBar, VictoryChart, VictoryAxis } from '../web_modules/victory.js';
3+
import htm from "../web_modules/htm.js";
4+
5+
const html = htm.bind(React.createElement);
6+
7+
const data = [
8+
{quarter: 1, earnings: 13000},
9+
{quarter: 2, earnings: 16500},
10+
{quarter: 3, earnings: 14250},
11+
{quarter: 4, earnings: 19000}
12+
];
13+
14+
class Chart extends React.Component {
15+
render() {
16+
return html`
17+
<${VictoryChart} domainPadding=20>
18+
<${VictoryAxis}
19+
tickValues=${[1, 2, 3, 4]}
20+
tickFormat=${["Quarter 1", "Quarter 2", "Quarter 3", "Quarter 4"]}
21+
/>
22+
<${VictoryAxis}
23+
dependentAxis
24+
tickFormat=${(x) => (`$${x / 1000}k`)}
25+
/>
26+
<${VictoryBar}
27+
data=${data}
28+
x="quarter"
29+
y="earnings"
30+
/>
31+
</${VictoryChart}>
32+
`
33+
}
34+
}
35+
36+
export default {Chart: Chart}

src/idom/widgets/display.py

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import uuid
2-
32
from typing import Any
3+
from urllib.parse import urlsplit, urlunsplit
4+
from IPython import display as _ipy_display
45

56

67
def display(kind: str, *args: Any, **kwargs: Any) -> Any:
@@ -18,31 +19,52 @@ def display(kind: str, *args: Any, **kwargs: Any) -> Any:
1819
class JupyterWigdet:
1920
"""Output for IDOM within a Jupyter Notebook."""
2021

21-
_shown = False
22-
__slots__ = "_url"
23-
_script = """
24-
import React from '{url}/web-modules/react.js';
25-
import ReactDOM from '{url}/web-modules/react-dom.js';
26-
import Layout from '{url}/js/idom-layout';
27-
28-
function IdomWidgetMount(endpoint, mountId) {
29-
const mount = document.getElementById(mountId);
30-
const element = React.createElement(Layout, {{endpoint: endpoint}})
31-
ReactDOM.render(element, mount);
32-
};
33-
"""
22+
_idom_server_exists_displayed = False
23+
__slots__ = ("_ws", "_http")
24+
25+
def __init__(self, url: str, secure=True) -> None:
26+
uri = urlunsplit(("",) + urlsplit(url)[1:])
27+
if uri.endswith("/"):
28+
uri = uri[:-1]
29+
if secure:
30+
ws_proto = "wss"
31+
http_proto = "https"
32+
else:
33+
ws_proto = "ws"
34+
http_proto = "http"
35+
self._ws = ws_proto + ":" + uri
36+
self._http = http_proto + ":" + uri
37+
if not type(self)._idom_server_exists_displayed:
38+
_ipy_display.display_html(
39+
"<script>document.idomServerExists = true;</script>", raw=True,
40+
)
41+
_ipy_display.clear_output(wait=True)
42+
type(self)._idom_server_exists_displayed = True
3443

35-
def __init__(self, url: str) -> None:
36-
self._url = url
44+
def _script(self, mount_id):
45+
return f"""
46+
<script type="module">
47+
// we want to avoid making this request (in case of CORS)
48+
// unless we know an IDOM server is expected to respond
49+
if (document.idomServerExists) {{
50+
import("{self._http}/client/core_modules/layout.js").then(
51+
module => {{
52+
module.renderLayout(
53+
document.getElementById("{mount_id}"), "{self._ws}/stream"
54+
)
55+
}}
56+
)
57+
}}
58+
</script>
59+
"""
3760

3861
def _repr_html_(self) -> str:
3962
"""Rich HTML display output."""
4063
mount_id = uuid.uuid4().hex
4164
return f"""
4265
<div id="{mount_id}"/>
43-
{'' if JupyterWigdet._shown else '<script>' + self._script + '</script>'}
44-
<script>window.IdomWidgetMount("{self._url}", "{mount_id}")</script>
66+
{self._script(mount_id)}
4567
"""
4668

4769
def __repr__(self) -> str:
48-
return "%s(%r)" % (type(self).__name__, self._url)
70+
return "%s(%r)" % (type(self).__name__, self._http)

0 commit comments

Comments
 (0)