Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,5 +99,34 @@ window.app = createApp({
},
loadExampleCredential(event) {
this.loadCredential(event.target.value);
},
setupMessaging(el) {
const iframe = el;
const loader = el.nextElementSibling;
// create a MessageChannel; transfer one port to the iframe
const channel = new MessageChannel();
// start message queue so messages won't be lost while iframe loads
channel.port1.start();
// handle `ready` message
channel.port1.onmessage = function(event) {
if(event.data?.ready) {
iframe.removeAttribute('hidden');
loader.setAttribute('hidden', 'hidden');
if(event.data?.pdf) {
// append another iframe after the current one with the PDF data URL
const pdfDownloadLink = document.createElement('a');
pdfDownloadLink.href = event.data.pdf;
pdfDownloadLink.download = 'credential.pdf';
pdfDownloadLink.textContent = 'Download PDF';
pdfDownloadLink.type = 'application/pdf';
iframe.insertAdjacentElement('afterend', pdfDownloadLink);
}
} else {
new Error(event.data?.error?.message);
}
channel.port1.onmessage = undefined;
};
// send "start" message; send `port2` to iframe for return communication
iframe.contentWindow.postMessage('start', '*', [channel.port2]);
}
}).mount();
8 changes: 7 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,13 @@
@click="currentTab = 'credential'">Filtered Credential</div>
</div>
<div class="ui bottom attached tab segment" :class="{ active: currentTab == 'rendered' }">
<iframe sandbox="allow-scripts allow-modals" :srcdoc="shimCode()" style="width: 100%; border: none;"></iframe>
<iframe sandbox="allow-scripts allow-modals"
hidden
:srcdoc="shimCode()"
@load="setupMessaging($el)"
style="width: 100%; border: none;"></iframe>
<!-- loader shown until the above iframe is ready -->
<div class="ui placeholder"><div class="image"></div></div>
</div>
<div class="ui bottom attached tab segment" :class="{ active: currentTab == 'code' }">
<div class="ui form">
Expand Down
20 changes: 20 additions & 0 deletions viewers/html.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,26 @@ export function HTMLViewer({template, credential, pointers}) {
<head>
<meta http-equiv="content-security-policy" content="default-src data: 'unsafe-inline'">
<script name="credential" type="application/vc">${store.filteredCredential}</script>
<script>
// add promise that will resolve to the communication port from
// the parent window
const portPromise = new Promise(resolve => {
window.addEventListener('message', function start(event) {
if(event.data === 'start' && event.ports?.[0]) {
window.removeEventListener('message', start);
resolve(event.ports[0]);
}
});
});

// attach a function to the window for the template to call when
// it's "ready" (or that an error occurred) that will send a message
// to the parent so the parent can decide whether to show the iframe
window.renderMethodReady = function(resp) {
portPromise.then(port => port.postMessage(
!resp.error ? resp : {error: {message: resp.error.message}}));
};
Comment on lines +54 to +57

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we'll want a different name than renderMethodReady if we're going to pass other things -- or at least, we don't want to have both {ready: true} and renderMethodReady as the names, it seems redundant. Maybe it's the {ready: true} that should change -- and passing any object at all is optional.

</script>
</head>
<body>
${store.code}
Expand Down