fix: receive XBlock visibility from the Learning MFE (#35491)

This commit is contained in:
Piotr Surowiec
2024-10-01 17:07:41 +02:00
committed by GitHub
parent d59c596fdf
commit 341537221e

View File

@@ -109,7 +109,13 @@ export class ViewedEventTracker {
constructor() {
this.elementViewings = new Set();
this.handlers = [];
this.registerDomHandlers();
if (window === window.parent) {
// Preview (legacy LMS frontend).
this.registerDomHandlers();
} else {
// Learning MFE.
window.addEventListener('message', this.handleVisibilityMessage.bind(this));
}
}
/** Add an element to track. */
@@ -121,7 +127,11 @@ export class ViewedEventTracker {
(el, event) => this.callHandlers(el, event),
),
);
this.updateVisible();
// Update visibility status immediately after adding the element (in case it's already visible).
// We don't need this for the Learning MFE because it will send a message once the iframe is loaded.
if (window === window.parent) {
this.updateVisible();
}
}
/** Register a new handler to be called when an element has been viewed. */
@@ -177,4 +187,36 @@ export class ViewedEventTracker {
handler(el, event);
});
}
/** Handle a unit.visibilityStatus message from the Learning MFE. */
handleVisibilityMessage(event) {
if (event.data.type === 'unit.visibilityStatus') {
const { topPosition, viewportHeight } = event.data.data;
this.elementViewings.forEach((elv) => {
const rect = elv.getBoundingRect();
let visible = false;
// Convert iframe-relative rect coordinates to be relative to the parent's viewport.
const elTopPosition = rect.top + topPosition;
const elBottomPosition = rect.bottom + topPosition;
// Check if the element is visible in the parent's viewport.
if (elTopPosition < viewportHeight && elTopPosition >= 0) {
elv.markTopSeen();
visible = true;
}
if (elBottomPosition <= viewportHeight && elBottomPosition > 0) {
elv.markBottomSeen();
visible = true;
}
if (visible) {
elv.handleVisible();
} else {
elv.handleNotVisible();
}
});
}
}
}