feat: add xblockScroll event handler to iframeMessageTypes (#2363)

* fix: new message type to scroll outer window to xblock location

* fix: reset after testing

* fix: formatting

* test: add test coverage

* fix: fix test mocks

* fix: formatting

* fix: add smooth to scroll
This commit is contained in:
Sara Burns
2025-08-15 09:11:21 -04:00
committed by GitHub
parent b2203f0ece
commit be82e96e6f
3 changed files with 47 additions and 1 deletions

View File

@@ -105,4 +105,5 @@ export const iframeMessageTypes = {
resize: 'plugin.resize',
videoFullScreen: 'plugin.videoFullScreen',
xblockEvent: 'xblock-event',
xblockScroll: 'xblock-scroll',
};

View File

@@ -122,8 +122,42 @@ describe('useIframeBehavior', () => {
expect(setWindowTopOffset).toHaveBeenCalledWith(window.scrollY);
});
it('handles xblockScroll message correctly', () => {
const iframeElement = document.createElement('iframe');
iframeElement.setAttribute('name', 'xblock-iframe');
Object.defineProperty(iframeElement, 'offsetTop', { writable: true, configurable: true, value: 50 });
const iframeParentElement = document.createElement('div');
iframeParentElement.setAttribute('id', 'div0');
Object.defineProperty(iframeParentElement, 'offsetTop', { writable: true, configurable: true, value: 25 });
iframeParentElement.appendChild(iframeElement);
document.body.appendChild(iframeParentElement);
renderHook(() => useIframeBehavior({ id, iframeUrl, iframeRef }));
const message = {
data: {
type: iframeMessageTypes.xblockScroll,
offset: 100,
},
};
act(() => {
window.dispatchEvent(new MessageEvent('message', message));
});
expect(window.scrollTo).toHaveBeenCalledWith({ top: 175, left: 0, behavior: 'smooth' });
expect(window.scrollY).toBe(100 + document.getElementsByName('xblock-iframe')[0].offsetTop + document.getElementsByName('xblock-iframe')[0]!.parentElement!.offsetTop);
});
it('handles offset message correctly', () => {
document.body.innerHTML = '<div id="unit-iframe" style="position: absolute; top: 50px;"></div>';
const iframeElement = document.createElement('iframe');
iframeElement.setAttribute('id', 'unit-iframe');
Object.defineProperty(iframeElement, 'offsetTop', { writable: true, configurable: true, value: 50 });
document.body.appendChild(iframeElement);
renderHook(() => useIframeBehavior({ id, iframeUrl, iframeRef }));
const message = {
@@ -134,6 +168,7 @@ describe('useIframeBehavior', () => {
window.dispatchEvent(new MessageEvent('message', message));
});
expect(window.scrollTo).toHaveBeenCalledWith(0, 150);
expect(window.scrollY).toBe(100 + (document.getElementById('unit-iframe') as HTMLElement).offsetTop);
});

View File

@@ -83,6 +83,16 @@ export const useIframeBehavior = ({
});
}
break;
case iframeMessageTypes.xblockScroll:
if (document.getElementsByName('xblock-iframe')) {
const iframeElement = document.getElementsByName('xblock-iframe')[0];
window.scrollTo({
top: data.offset + iframeElement!.offsetTop + iframeElement.parentElement!.offsetTop,
left: 0,
behavior: 'smooth',
});
}
break;
default:
if (data.offset) {
// We listen for this message from LMS to know when the page needs to