Skip to content

Commit 80343d0

Browse files
Michal Kočáreksmeijer
andauthored
feat: allow dynamic updates of query and markup from embedding window (#275)
Co-authored-by: Stephan Meijer <[email protected]>
1 parent 0962018 commit 80343d0

File tree

4 files changed

+103
-0
lines changed

4 files changed

+103
-0
lines changed

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,38 @@ To configure your playground even further, add one or more of the following attr
8181
| data-width | number &#124; string | '100% ' | width of the element |
8282
| data-loading | eager &#124; lazy | 'lazy' | load the frame eager or lazy (see iframe specs) |
8383

84+
#### dynamic updates
85+
86+
Playground can be updated using [cross-window messaging](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage)
87+
after it has been loaded. After the playground is loaded, you can update it with following message: `{type: 'UPDATE_DATA', markup: 'new markup', query: 'new query'}` with both `markup` and `query` being optional.
88+
89+
To find out, if playground is ready, you can listen for a message `{source: 'embedded-testing-playground', type: 'READY'}`
90+
in window from which are you embedding the playground.
91+
92+
Example:
93+
94+
```html
95+
<template data-testing-playground data-class="messaging-iframe"></template>
96+
<script type="text/javascript">
97+
function updatePlayground() {
98+
const iframe = document.querySelector('.messaging-iframe');
99+
iframe.contentWindow.postMessage(
100+
{ type: 'UPDATE_DATA', markup: 'new markup', query: 'new query' },
101+
'https://testing-playground.com',
102+
);
103+
}
104+
105+
window.addEventListener('message', ({ data }) => {
106+
if (
107+
data.source === 'embedded-testing-playground' &&
108+
data.type === 'READY'
109+
) {
110+
updatePlayground();
111+
}
112+
});
113+
</script>
114+
```
115+
84116
## Roadmap
85117

86118
Future ideas are maintained in [roadmap.md]. Please use the [issue tracker] to discuss any questions or suggestions you have.
@@ -127,6 +159,7 @@ Thanks goes to these people ([emoji key][emojis]):
127159

128160
<!-- markdownlint-enable -->
129161
<!-- prettier-ignore-end -->
162+
130163
<!-- ALL-CONTRIBUTORS-LIST:END -->
131164

132165
This project follows the [all-contributors][all-contributors] specification.

src/components/Embedded.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Preview from './Preview';
55
import Query from './Query';
66
import Result from './Result';
77
import MarkupEditor from './MarkupEditor';
8+
import useParentMessaging from '../hooks/useParentMessaging';
89
import usePlayground from '../hooks/usePlayground';
910
import Loader from './Loader';
1011

@@ -67,6 +68,8 @@ function Embedded(props) {
6768
return () => document.body.classList.remove('embedded');
6869
}, []);
6970

71+
useParentMessaging(dispatch);
72+
7073
return (
7174
<div className="relative w-full h-full">
7275
<Loader loading={isLoading} />

src/embed.html

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,23 @@
5555
</script>
5656
</template>
5757

58+
<template data-testing-playground data-class="messaging-iframe"></template>
59+
<script type="text/javascript">
60+
function updatePlayground() {
61+
const iframe = document.querySelector('.messaging-iframe');
62+
iframe.contentWindow.postMessage(
63+
{ type: 'UPDATE_DATA', markup: 'new markup', query: 'new query' },
64+
'http://localhost:1234',
65+
);
66+
}
67+
68+
window.addEventListener('message', ({ data }) => {
69+
if (data.source === 'embedded-testing-playground' && data.type === 'READY') {
70+
updatePlayground();
71+
}
72+
});
73+
</script>
74+
5875
<script async src="embed.js"></script>
5976
</body>
6077
</html>

src/hooks/useParentMessaging.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { useEffect } from 'react';
2+
3+
function dispatchUpdateData(dispatch, { markup, query }) {
4+
if (markup !== undefined) {
5+
dispatch({ type: 'SET_MARKUP', markup });
6+
}
7+
8+
if (query !== undefined) {
9+
dispatch({ type: 'SET_QUERY', query });
10+
}
11+
}
12+
13+
function useParentMessaging(dispatch) {
14+
useEffect(() => {
15+
if (window === parent) {
16+
return;
17+
}
18+
19+
const listener = ({ source, target, data }) => {
20+
if (source !== parent) {
21+
return;
22+
}
23+
24+
if (target !== window) {
25+
return;
26+
}
27+
28+
switch (data.type) {
29+
case 'UPDATE_DATA':
30+
dispatchUpdateData(dispatch, data);
31+
break;
32+
default:
33+
return;
34+
}
35+
};
36+
37+
window.addEventListener('message', listener);
38+
39+
parent.postMessage(
40+
{
41+
source: 'embedded-testing-playground',
42+
type: 'READY',
43+
},
44+
'*', // We don't know parent origin, so we have to send it to whoever is there
45+
);
46+
return () => window.removeEventListener('message', listener);
47+
}, [dispatch]);
48+
}
49+
50+
export default useParentMessaging;

0 commit comments

Comments
 (0)