Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Lancement et hauteur automatiques d'embed (PIX-13211) #9406

Merged
merged 5 commits into from
Jul 8, 2024
Merged
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
24 changes: 13 additions & 11 deletions mon-pix/app/components/challenge-embed-simulator.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,18 @@
></iframe>
</div>

<div class="embed__reboot">
<button
type="button"
class="link link--grey embed-reboot__content"
aria-label={{t "pages.challenge.embed-simulator.actions.reset-label"}}
{{on "click" this.rebootSimulator}}
>
<FaIcon @icon="rotate-right" class="embed-reboot-content__icon" />
{{t "pages.challenge.embed-simulator.actions.reset"}}
</button>
</div>
{{#if this.isSimulatorRebootable}}
<div class="embed__reboot">
<button
type="button"
class="link link--grey embed-reboot__content"
aria-label={{t "pages.challenge.embed-simulator.actions.reset-label"}}
{{on "click" this.rebootSimulator}}
>
<FaIcon @icon="rotate-right" class="embed-reboot-content__icon" />
{{t "pages.challenge.embed-simulator.actions.reset"}}
</button>
</div>
{{/if}}
</div>
</div>
89 changes: 75 additions & 14 deletions mon-pix/app/components/challenge-embed-simulator.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,22 @@ export default class ChallengeEmbedSimulator extends Component {
@tracked
isSimulatorLaunched = false;

@tracked
isSimulatorRebootable = true;

@tracked
embedHeight;

_embedMessageListener;

constructor(owner, args) {
super(owner, args);
this.embedHeight = args.embedDocument?.height;
}

get embedDocumentHeightStyle() {
if (this.args.embedDocument) {
return htmlSafe(`height: ${this.args.embedDocument.height}px`);
if (this.embedHeight) {
return htmlSafe(`height: ${this.embedHeight}px`);
}
return '';
}
Expand All @@ -33,25 +46,36 @@ export default class ChallengeEmbedSimulator extends Component {
};

iframe.addEventListener('load', loadListener);

thisComponent._embedMessageListener = ({ origin, data }) => {
if (!isEmbedAllowedOrigin(origin)) return;
if (isReadyMessage(data) && thisComponent.isSimulatorLaunched) {
iframe.contentWindow.postMessage('launch', '*');
iframe.focus();
}
if (isHeightMessage(data)) {
thisComponent.embedHeight = data.height + 20;
}
if (isAutoLaunchMessage(data)) {
thisComponent.launchSimulator();
thisComponent.isSimulatorRebootable = false;
}
};

window.addEventListener('message', thisComponent._embedMessageListener);
}

@action
launchSimulator(event) {
const iframe = this._getIframe(event);
launchSimulator() {
const iframe = this.iframe;
iframe.contentWindow.postMessage('launch', '*');
iframe.focus();
this.isSimulatorLaunched = true;
window.addEventListener('message', (e) => {
if (!isEmbedAllowedOrigin(e.origin)) return;
if (typeof e.data !== 'object' || e.data.from !== 'pix' || e.data.type !== 'ready') return;
iframe.contentWindow.postMessage('launch', '*');
iframe.focus();
});
}

@action
rebootSimulator(event) {
const iframe = this._getIframe(event);
rebootSimulator() {
const iframe = this.iframe;
const tmpSrc = iframe.src;

const loadListener = () => {
Expand All @@ -71,7 +95,44 @@ export default class ChallengeEmbedSimulator extends Component {
iframe.src = 'about:blank';
}

_getIframe(event) {
return event.currentTarget.parentElement.parentElement.querySelector('.embed__iframe');
willDestroy() {
super.willDestroy();
window.removeEventListener('message', this._embedMessageListener);
}

get iframe() {
return document.querySelector('.embed__iframe');
}
}

/**
* Checks if event is a "ready" message.
* @param {unknown} data
* @returns {boolean}
*/
function isReadyMessage(data) {
return isMessageType(data, 'ready');
}

/**
* Checks if event is a "height" message.
* @param {unknown} data
* @returns {data is { height: number }}
*/
function isHeightMessage(data) {
return isMessageType(data, 'height');
}

/**
* Checks if event is a "auto-launch" message.
* @param {unknown} data
* @returns {boolean}
*/
function isAutoLaunchMessage(data) {
return isMessageType(data, 'auto-launch');
}

function isMessageType(data, type) {
if (typeof data !== 'object' || data === null) return false;
return data.from === 'pix' && data.type === type;
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ module('Integration | Component | Challenge Embed Simulator', function (hooks) {
});

module('Embed simulator', function (hooks) {
let screen;

hooks.beforeEach(async function () {
// given
this.set('embedDocument', {
Expand All @@ -82,9 +84,7 @@ module('Integration | Component | Challenge Embed Simulator', function (hooks) {
});

// when
await render(hbs`<ChallengeEmbedSimulator @embedDocument={{this.embedDocument}} />`);

// then
screen = await render(hbs`<ChallengeEmbedSimulator @embedDocument={{this.embedDocument}} />`);
});

test('should have an height that is the one defined in the referential', function (assert) {
Expand All @@ -98,5 +98,34 @@ module('Integration | Component | Challenge Embed Simulator', function (hooks) {
test('should define a src attribute on the iframe element that is the one defined in the referential for field "Embed URL"', function (assert) {
assert.strictEqual(find('.embed__iframe').src, 'http://embed-simulator.url/');
});

module('when embed sends its height', function () {
test('should listen for embed height and resize iframe container', async function (assert) {
const event = new MessageEvent('message', {
data: { from: 'pix', type: 'height', height: 480 },
origin: 'https://epreuves.pix.fr',
});
window.dispatchEvent(event);

await new Promise((resolve) => setTimeout(resolve, 0));

assert.strictEqual(find('.embed__iframe').style.cssText, 'height: 500px;');
});
});

module('when embed auto launches', function () {
test('should not display launch button and reboot button', async function (assert) {
const event = new MessageEvent('message', {
data: { from: 'pix', type: 'auto-launch' },
origin: 'https://epreuves.pix.fr',
});
window.dispatchEvent(event);

await new Promise((resolve) => setTimeout(resolve, 0));

assert.dom(screen.queryByText(this.intl.t('pages.challenge.embed-simulator.actions.launch'))).doesNotExist();
assert.dom(screen.queryByText(this.intl.t('pages.challenge.embed-simulator.actions.reset'))).doesNotExist();
});
});
});
});