Iframe integration
A space (URL provided by Fast4) can be displayed in two ways:
- "as it is" meaning the URL is directly loaded in the browser
- in an
iframe
to be integrated in another web site
iframe
The space URL can be integrated in another web site by adding this element:
<iframe id="spacePage" title="Space page" src="http://demo.simspace.fr" frameborder="0"></iframe>
Here is a basic example to integrate the iframe:
<html>
<head>
<title>Space page sample</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.1/dist/css/bootstrap.min.css"
rel="stylesheet"
/>
<link
href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css"
rel="stylesheet"
/>
<script src="https://code.jquery.com/jquery-3.6.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>
<script src="space.js"></script>
</head>
<body>
<h1>Space page sample</h1>
<button onclick="logout()">Logout</button>
<div class="container">
<iframe
class="w-100 h-100"
frameborder="0"
id="spacePage"
title="Space page"
src="https://demo.simspace.fr"
>
</iframe>
</div>
</body>
</html>
window.onmessage = function (event) {
// Ensure the event comes from the Simspace iframe
if (event.origin === 'https://demo.simspace.fr') {
if (event.data.type === 'CHAT_SCROLL') {
window.scrollTo(0, document.body.scrollHeight)
} else {
toastr.info('New message received: ' + JSON.stringify(event.data))
}
}
}
function logout() {
const iframe = document.querySelector('iframe')
iframe.contentWindow.postMessage({ type: 'LOGOUT' }, 'https://demo.simspace.fr')
}
The javascript file is used to intercept the events sent by the iframe. Please refer to the details here-below.
Please ensure that the events come from the Simspace iframe by checking the origin
property.
Events published by the iframe
The iframe send events to parent page through the postMessage API.
These events can be intercepted in the parent page by using the window.onmessage = function (event) {}
method (see sample above).
Each event data got the type
property to identify the event type (see all supported types below).
Other fields can be added depending on the event type.
Warning
Some new events can be added on futures deliveries, so you should consider not to be too strict on events types. For instance, enum are too strict, and if a new event type is added, your code will crash!
Here is the message structure in Typescript:
export type SimspacePMEvent =
| {
type: 'LOGIN' | 'LOGOUT'
player: PlayerPMInfo
}
| {
type: 'GAME_START' | 'GAME_ABANDON' | 'GAME_COMPLETE'
player: PlayerPMInfo
simulation: SimulationPMInfo
game: GamePMInfo
}
| {
type: 'SIMULATION_NOT_PLAYABLE'
player: PlayerPMInfo
simulation: SimulationPMInfo
}
| {
type: 'GAME_PLAYER_INPUT'
player: PlayerPMInfo
simulation: SimulationPMInfo
game: GamePMInfo
step: { id: number; name: string }
playerInput: IPlayerInput
}
| {
type: 'CHAT_SCROLL'
}
export type SimulationPMInfo = {
id: number
code: string
name: string
}
export type PlayerPMInfo = {
id: number
identifier: string
}
export type GamePMInfo = {
id: number
}
export type IPlayerInput =
| {
type: 'multiple'
answers: IPlayerAnswer[]
}
| {
type: 'single'
answer: IPlayerAnswer
}
| {
type: 'free-text'
text: string
}
| {
type: 'action'
action: 'RESET' | 'EXIT'
}
export interface IPlayerAnswer {
id: number
label: string
}
Login event
The type of this event is LOGIN
.
It is sent after the player just logged in into the space. Only the player
is provided for this event.
{
"type": "LOGIN",
"player": { "id": 10, "identifier": "user-123" }
}
Logout event
The type of this event is LOGOUT
.
It is sent after the player logged out or when his session has expired. Only the player
is provided for this event.
You might want to listen to this event if you are responsible for logging the player programmatically through the access token mechanism.
{
"type": "LOGOUT",
"player": { "id": 10, "identifier": "user-123" }
}
Game start event
The type of this event is GAME_START
.
It is sent when a player just start a new game.
{
"type": "GAME_START",
"player": { "id": 10, "identifier": "user-123" },
"simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" },
"game": { "id": 15 }
}
Game complete event
The type of this event is GAME_COMPLETE
.
It is sent when a player just complete a game.
{
"type": "GAME_COMPLETE",
"player": { "id": 10, "identifier": "user-123" },
"simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" },
"game": { "id": 15 }
}
Game abandon event
The type of this event is GAME_ABANDON
.
It is sent when a player just abandon a game.
{
"type": "GAME_ABANDON",
"player": { "id": 10, "identifier": "user-123" },
"simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" },
"game": { "id": 15 }
}
Player input in chat
The type of this event is GAME_PLAYER_INPUT
.
It is sent when a player just type an input in the chat.
{
"type": "GAME_PLAYER_INPUT",
"player": { "id": 10, "identifier": "user-123" },
"simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" },
"game": { "id": 15 },
"step": { "id": 5, "name": "my step" },
"playerInput": {
"type": "MULTIPLE",
"answers": [
{ "id": 3, "label": "Lorem ipsum dolor sit amet" },
{ "id": 5, "label": "Donec sit amet mollis nibh" }
]
}
}
This event has additional fields:
step
the step in the simulation using the input (identified by itsid
andname
)playerInput
the answers of the step
Simulation not playable
This event use the SIMULATION_NOT_PLAYABLE
type.
This event is sent only if:
- you use the simulation standalone mode
- the simulations cannot be replayed
So it happens:
- if the simulation replay option is disabled and you try to replay a simulation
- or if the sequential simulations option is enabled and you try to start a simulation in the wrong order
{
"type": "SIMULATION_NOT_PLAYABLE",
"player": { "id": 10, "identifier": "user-123" },
"simulation": { "id": 12, "code": "my-simulation", "name": "My Simulation" }
}
Chat scroll event
The type of this event is CHAT_SCROLL
.
{
"type": "CHAT_SCROLL"
}
This event is sent every time the chat automatically scrolls.
It may be used by the iframe container to adjust its own scroll, for e.g.:
window.onmessage = function (event) {
// [...]
if (event.data.type === 'CHAT_SCROLL') {
window.scrollTo(0, document.body.scrollHeight)
}
}
Events published by the parent page
The parent page mainly receive events from the iframe, but it can also send some.
The implementation is easy:
function logout() {
const iframe = document.querySelector('iframe')
const message = { type: 'LOGOUT' }
iframe.contentWindow.postMessage(message, 'https://demo.simspace.fr')
}
In this example we select the unique iframe in the web page and we send it the message.
Warning
It is highly recommended to set the target
parameter in postMessage
. In our case, this is the iframe host.
Player logout
If you use a space with credentials, if the player is logged out from your web site you probably want to log him out
from the iframe. To do so, you have to send the message { type: 'LOGOUT
}.
iframe.contentWindow.postMessage({ type: 'LOGOUT' }, 'https://demo.simspace.fr')
Standalone simulation
The iframe can be used in "standalone mode", meaning the navigation buttons on game page are not displayed. This is useful if you want to only display a game without showing the simulations page.
To use this mode, you must add the query parameter standaloneSimulation=true
.
https://demo.simspace.fr/player/simulations/simu-1/game?standaloneSimulation=true
The simu-1
is the unique code to identify the simulation.
This mode only works for the game page.
If the space is secured by credentials, you can use both "access-token" and "standalone mode".
https://demo.simspace.fr/player/simulations/simu-1/game?standaloneSimulation=true&accessToken=f38bbdfc-5f4f-11ed-a962-0f7cc96827e1