diff --git a/src/constants.js b/src/constants.js index b1c84e921f..beb4a74d1f 100644 --- a/src/constants.js +++ b/src/constants.js @@ -105,4 +105,5 @@ export const iframeMessageTypes = { resize: 'plugin.resize', videoFullScreen: 'plugin.videoFullScreen', xblockEvent: 'xblock-event', + xblockScroll: 'xblock-scroll', }; diff --git a/src/generic/hooks/tests/hooks.test.tsx b/src/generic/hooks/tests/hooks.test.tsx index ef1bbb3039..4a22b9d149 100644 --- a/src/generic/hooks/tests/hooks.test.tsx +++ b/src/generic/hooks/tests/hooks.test.tsx @@ -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(0, 175); + 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 = '
'; + 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); }); diff --git a/src/generic/hooks/useIframeBehavior.tsx b/src/generic/hooks/useIframeBehavior.tsx index 7d50d1e0fb..b264735129 100644 --- a/src/generic/hooks/useIframeBehavior.tsx +++ b/src/generic/hooks/useIframeBehavior.tsx @@ -83,6 +83,12 @@ export const useIframeBehavior = ({ }); } break; + case iframeMessageTypes.xblockScroll: + if (document.getElementsByName('xblock-iframe')) { + const iframeElement = document.getElementsByName('xblock-iframe')[0]; + window.scrollTo(0, data.offset + iframeElement!.offsetTop + iframeElement.parentElement!.offsetTop); + } + break; default: if (data.offset) { // We listen for this message from LMS to know when the page needs to